summaryrefslogtreecommitdiff
path: root/sys/arch/mvme68k
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1996-04-28 11:24:50 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1996-04-28 11:24:50 +0000
commit04e89f5b87e945cfe47ccf26d7763132c96772fd (patch)
tree0ed05bc667dbf2012b55cbbcd38e3bea3de71d4c /sys/arch/mvme68k
parente992baf34a7d09967be6b437c6413b990896c5fd (diff)
wdsc driver hacked from amiga driver by Steve Woodford
Diffstat (limited to 'sys/arch/mvme68k')
-rw-r--r--sys/arch/mvme68k/conf/GENERIC6
-rw-r--r--sys/arch/mvme68k/conf/MVME1476
-rw-r--r--sys/arch/mvme68k/conf/MVME1626
-rw-r--r--sys/arch/mvme68k/conf/MVME1676
-rw-r--r--sys/arch/mvme68k/dev/dmavar.h30
-rw-r--r--sys/arch/mvme68k/dev/sbic.c4439
-rw-r--r--sys/arch/mvme68k/dev/sbicreg.h465
-rw-r--r--sys/arch/mvme68k/dev/sbicvar.h287
-rw-r--r--sys/arch/mvme68k/dev/wdsc.c349
-rw-r--r--sys/arch/mvme68k/dev/wdscreg.h53
10 files changed, 3072 insertions, 2575 deletions
diff --git a/sys/arch/mvme68k/conf/GENERIC b/sys/arch/mvme68k/conf/GENERIC
index 306768af648..649d126da18 100644
--- a/sys/arch/mvme68k/conf/GENERIC
+++ b/sys/arch/mvme68k/conf/GENERIC
@@ -1,4 +1,4 @@
-# $Id: GENERIC,v 1.4 1995/11/23 13:13:26 deraadt Exp $
+# $OpenBSD: GENERIC,v 1.5 1996/04/28 11:24:33 deraadt Exp $
machine mvme68k m68k
@@ -59,7 +59,7 @@ nvram0 at pcc0 offset 0x0000
zs0 at pcc0 offset 0x3000 ipl 4
zs1 at pcc0 offset 0x3800 ipl 4
le0 at pcc0 offset 0x1800 ipl 1
-sbic0 at pcc0 offset 0x4000 ipl 2
+wdsc0 at pcc0 offset 0x4000 ipl 2
lp0 at pcc0 ipl 1
vme0 at pcc0 offset 0x2000
@@ -98,7 +98,7 @@ bugtty0 at mainbus0
vmes0 at vme0
vmel0 at vme0
-scsibus* at sbic?
+scsibus* at wdsc?
scsibus* at siop?
sd* at scsibus? target ? lun ?
diff --git a/sys/arch/mvme68k/conf/MVME147 b/sys/arch/mvme68k/conf/MVME147
index a1d2f866a59..7a1cc2f46fd 100644
--- a/sys/arch/mvme68k/conf/MVME147
+++ b/sys/arch/mvme68k/conf/MVME147
@@ -1,4 +1,4 @@
-# $Id: MVME147,v 1.4 1995/11/23 13:13:27 deraadt Exp $
+# $OpenBSD: MVME147,v 1.5 1996/04/28 11:24:34 deraadt Exp $
machine mvme68k m68k
@@ -53,14 +53,14 @@ nvram0 at pcc0 offset 0x0000
zs0 at pcc0 offset 0x3000 ipl 4
zs1 at pcc0 offset 0x3800 ipl 4
le0 at pcc0 offset 0x1800 ipl 1
-sbic0 at pcc0 offset 0x4000 ipl 2
+wdsc0 at pcc0 offset 0x4000 ipl 2
lp0 at pcc0 ipl 1
vme0 at pcc0 offset 0x2000
vmes0 at vme0
vmel0 at vme0
-scsibus* at sbic?
+scsibus* at wdsc?
sd* at scsibus? target ? lun ?
st* at scsibus? target ? lun ?
diff --git a/sys/arch/mvme68k/conf/MVME162 b/sys/arch/mvme68k/conf/MVME162
index a0d92a815b2..b81919a3658 100644
--- a/sys/arch/mvme68k/conf/MVME162
+++ b/sys/arch/mvme68k/conf/MVME162
@@ -1,4 +1,4 @@
-# $Id: MVME162,v 1.4 1995/11/23 13:13:28 deraadt Exp $
+# $OpenBSD: MVME162,v 1.5 1996/04/28 11:24:38 deraadt Exp $
machine mvme68k m68k
@@ -57,7 +57,7 @@ mainbus0 at root
#zs0 at pcc0 offset 0x3000 ipl 4
#zs1 at pcc0 offset 0x3800 ipl 4
#le0 at pcc0 offset 0x1800 ipl 1
-#sbic0 at pcc0 offset 0x4000 ipl 2
+#wdsc0 at pcc0 offset 0x4000 ipl 2
##lp0 at pcc0 ipl 1
#vme0 at pcc0 offset 0x2000
@@ -100,7 +100,7 @@ vmel0 at vme0
#xdc0 at vmel0 addr 0xff00ee80 ipl 2 vec 0x44
#xd* at xdc? target ?
-#scsibus* at sbic?
+#scsibus* at wdsc?
scsibus* at siop?
sd* at scsibus? target ? lun ?
diff --git a/sys/arch/mvme68k/conf/MVME167 b/sys/arch/mvme68k/conf/MVME167
index 7c2f4b60443..fb3ab772ecd 100644
--- a/sys/arch/mvme68k/conf/MVME167
+++ b/sys/arch/mvme68k/conf/MVME167
@@ -1,4 +1,4 @@
-# $Id: MVME167,v 1.4 1995/11/23 13:13:28 deraadt Exp $
+# $OpenBSD: MVME167,v 1.5 1996/04/28 11:24:39 deraadt Exp $
machine mvme68k m68k
@@ -57,7 +57,7 @@ mainbus0 at root
#zs0 at pcc0 offset 0x3000 ipl 4
#zs1 at pcc0 offset 0x3800 ipl 4
#le0 at pcc0 offset 0x1800 ipl 1
-#sbic0 at pcc0 offset 0x4000 ipl 2
+#wdsc0 at pcc0 offset 0x4000 ipl 2
##lp0 at pcc0 ipl 1
#vme0 at pcc0 offset 0x2000
@@ -99,7 +99,7 @@ vmel0 at vme0
#xdc0 at vmel0 addr 0xff00ee80 ipl 2 vec 0x44
#xd* at xdc? target ?
-#scsibus* at sbic?
+#scsibus* at wdsc?
scsibus* at siop?
sd* at scsibus? target ? lun ?
diff --git a/sys/arch/mvme68k/dev/dmavar.h b/sys/arch/mvme68k/dev/dmavar.h
index a47d161eab7..b473a900ea1 100644
--- a/sys/arch/mvme68k/dev/dmavar.h
+++ b/sys/arch/mvme68k/dev/dmavar.h
@@ -1,9 +1,9 @@
-/* $Id: dmavar.h,v 1.2 1995/11/07 08:48:54 deraadt Exp $ */
+/* $OpenBSD: dmavar.h,v 1.3 1996/04/28 11:24:43 deraadt Exp $ */
/*
* Copyright (c) 1982, 1990 The Regents of the University of California.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -14,12 +14,12 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -32,18 +32,16 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)dmavar.h 7.2 (Berkeley) 11/4/90
- * $Id: dmavar.h,v 1.2 1995/11/07 08:48:54 deraadt Exp $
+ * @(#)dmavar.h 7.2 (Berkeley) 11/4/90
*/
-/* dmago flags */
-#define DMAGO_READ 0x08 /* transfer is a read */
-#define DMAGO_NOINT 0x80 /* don't interrupt on completion */
+/* dmago flags */
+#define DMAGO_READ 0x08 /* transfer is a read */
+#define DMAGO_NOINT 0x80 /* don't interrupt on completion */
-#ifdef KERNEL
-typedef void (*dmafree_t) __P((void *dev));
-typedef int (*dmago_t) __P((void *dev, char *, int, int));
-typedef int (*dmanext_t) __P((void *dev));
-typedef void (*dmastop_t) __P((void *dev));
+#ifdef _KERNEL
+typedef void (*dmafree_t) (void *dev);
+typedef int (*dmago_t) (void *dev, char *, int, int);
+typedef int (*dmanext_t) (void *dev);
+typedef void (*dmastop_t) (void *dev);
#endif
-
diff --git a/sys/arch/mvme68k/dev/sbic.c b/sys/arch/mvme68k/dev/sbic.c
index 79849f180f9..d8faa00d799 100644
--- a/sys/arch/mvme68k/dev/sbic.c
+++ b/sys/arch/mvme68k/dev/sbic.c
@@ -1,7 +1,8 @@
-/* $Id: sbic.c,v 1.2 1995/11/07 08:49:24 deraadt Exp $ */
+/* $OpenBSD: sbic.c,v 1.3 1996/04/28 11:24:44 deraadt Exp $ */
/*
- * Copyright (c) 1994 Christian E. Hopps
+ * Changes Copyright (c) 1996 Steve Woodford
+ * Original Copyright (c) 1994 Christian E. Hopps
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
@@ -18,8 +19,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -36,11 +37,20 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)scsi.c 7.5 (Berkeley) 5/4/91
+ * @(#)scsi.c 7.5 (Berkeley) 5/4/91
*/
/*
- * AMD 33C93 scsi adaptor driver
+ * Steve Woodford (SCW), Apr, 1996
+ * MVME147S WD33C93 Scsi Bus Interface Controller driver,
+ *
+ * Basically a de-loused and tidied up version of the Amiga AMD 33C93 driver.
+ *
+ * The original driver used features which required at least a WD33C93A
+ * chip. The '147 has the original WD33C93 chip (no 'A' suffix).
+ *
+ * This version of the driver is pretty well generic, so should work with
+ * any flavour of WD33C93 chip.
*/
#include <sys/param.h>
@@ -55,246 +65,293 @@
#include <vm/vm.h>
#include <vm/vm_kern.h>
#include <vm/vm_page.h>
+#include <vm/pmap.h>
#include <machine/pmap.h>
-#include <machine/autoconf.h>
#include <mvme68k/dev/dmavar.h>
#include <mvme68k/dev/sbicreg.h>
#include <mvme68k/dev/sbicvar.h>
+#include <machine/autoconf.h>
+#include <mvme68k/dev/pccreg.h>
-#include <vm/pmap.h>
-/* Since I can't find this in any other header files */
-#define SCSI_PHASE(reg) (reg&0x07)
+/*
+ * Since I can't find this in any other header files
+ */
+#define SCSI_PHASE(reg) (reg&0x07)
/*
* SCSI delays
* In u-seconds, primarily for state changes on the SPC.
*/
-#define SBIC_CMD_WAIT 50000 /* wait per step of 'immediate' cmds */
-#define SBIC_DATA_WAIT 50000 /* wait per data in/out step */
-#define SBIC_INIT_WAIT 50000 /* wait per step (both) during init */
+#define SBIC_CMD_WAIT 50000 /* wait per step of 'immediate' cmds */
+#define SBIC_DATA_WAIT 50000 /* wait per data in/out step */
+#define SBIC_INIT_WAIT 50000 /* wait per step (both) during init */
-#define b_cylin b_resid
+/*
+ * Convenience macro for waiting for a particular sbic event
+ */
#define SBIC_WAIT(regs, until, timeo) sbicwait(regs, until, timeo, __LINE__)
extern u_int kvtop();
-int sbicicmd __P((struct sbic_softc *, int, int, void *, int, void *, int));
-int sbicgo __P((struct sbic_softc *, struct scsi_xfer *));
-int sbicdmaok __P((struct sbic_softc *, struct scsi_xfer *));
-int sbicwait __P((sbic_regmap_p, char, int , int));
-int sbiccheckdmap __P((void *, u_long, u_long));
-int sbicselectbus __P((struct sbic_softc *, sbic_regmap_p, u_char, u_char, u_char));
-int sbicxfstart __P((sbic_regmap_p, int, u_char, int));
-int sbicxfout __P((sbic_regmap_p regs, int, void *, int));
-int sbicfromscsiperiod __P((struct sbic_softc *, sbic_regmap_p, int));
-int sbictoscsiperiod __P((struct sbic_softc *, sbic_regmap_p, int));
-int sbicintr __P((struct sbic_softc *));
-int sbicpoll __P((struct sbic_softc *));
-int sbicnextstate __P((struct sbic_softc *, u_char, u_char));
-int sbicmsgin __P((struct sbic_softc *));
-int sbicxfin __P((sbic_regmap_p regs, int, void *));
-int sbicabort __P((struct sbic_softc *, sbic_regmap_p, char *));
-void sbicxfdone __P((struct sbic_softc *, sbic_regmap_p, int));
-void sbicerror __P((struct sbic_softc *, sbic_regmap_p, u_char));
-void sbicstart __P((struct sbic_softc *));
-void sbicreset __P((struct sbic_softc *));
-void sbic_scsidone __P((struct sbic_acb *, int));
-void sbic_sched __P((struct sbic_softc *));
-void sbic_save_ptrs __P((struct sbic_softc *, sbic_regmap_p,int,int));
-void sbic_load_ptrs __P((struct sbic_softc *, sbic_regmap_p,int,int));
+int sbicicmd __P((struct sbic_softc *, void *, int, void *, int));
+int sbicgo __P((struct sbic_softc *, struct scsi_xfer *));
+int sbicdmaok __P((struct sbic_softc *, struct scsi_xfer *));
+int sbicwait __P((sbic_regmap_p, u_char, int , int));
+int sbiccheckdmap __P((void *, u_long, u_long));
+u_char sbicselectbus __P((struct sbic_softc *));
+int sbicxfout __P((sbic_regmap_p, int, void *));
+int sbicxfin __P((sbic_regmap_p, int, void *));
+int sbicfromscsiperiod __P((struct sbic_softc *, int));
+int sbictoscsiperiod __P((struct sbic_softc *, int));
+int sbicintr __P((struct sbic_softc *));
+int sbicpoll __P((struct sbic_softc *));
+int sbicnextstate __P((struct sbic_softc *, u_char, u_char));
+int sbicmsgin __P((struct sbic_softc *));
+int sbicabort __P((struct sbic_softc *, char *));
+void sbicxfdone __P((struct sbic_softc *));
+void sbicerror __P((struct sbic_softc *,u_char));
+void sbicreset __P((struct sbic_softc *));
+void sbic_scsidone __P((struct sbic_acb *, int));
+void sbic_sched __P((struct sbic_softc *));
+void sbic_save_ptrs __P((struct sbic_softc *));
+void sbic_load_ptrs __P((struct sbic_softc *));
/*
* Synch xfer parameters, and timing conversions
*/
-int sbic_min_period = SBIC_SYN_MIN_PERIOD; /* in cycles = f(ICLK,FSn) */
-int sbic_max_offset = SBIC_SYN_MAX_OFFSET; /* pure number */
-
-int sbic_cmd_wait = SBIC_CMD_WAIT;
-int sbic_data_wait = SBIC_DATA_WAIT;
-int sbic_init_wait = SBIC_INIT_WAIT;
+int sbic_min_period = SBIC_SYN_MIN_PERIOD; /* in cycles = f(ICLK,FSn) */
+int sbic_max_offset = SBIC_SYN_MAX_OFFSET; /* pure number */
+int sbic_cmd_wait = SBIC_CMD_WAIT;
+int sbic_data_wait = SBIC_DATA_WAIT;
+int sbic_init_wait = SBIC_INIT_WAIT;
/*
* was broken before.. now if you want this you get it for all drives
* on sbic controllers.
*/
-int sbic_inhibit_sync = 1;
-int sbic_enable_reselect = 1;
-int sbic_clock_override = 0;
-int sbic_no_dma = 0;
-int sbic_parallel_operations = 1;
+u_char sbic_inhibit_sync[8];
+int sbic_enable_reselect = 1; /* Allow Disconnect / Reselect */
+int sbic_no_dma = 0; /* Use PIO transfers instead of DMA */
+int sbic_parallel_operations = 1; /* Allow command queues */
+/*
+ * Some useful stuff for debugging purposes
+ */
#ifdef DEBUG
-sbic_regmap_p debug_sbic_regs;
-int sbicdma_ops = 0; /* total DMA operations */
-int sbicdma_bounces = 0; /* number operations using bounce buffer */
-int sbicdma_hits = 0; /* number of DMA chains that were contiguous */
-int sbicdma_misses = 0; /* number of DMA chains that were not contiguous */
-int sbicdma_saves = 0;
+int sbicdma_ops = 0; /* total DMA operations */
+int sbicdma_hits = 0; /* number of DMA chains that were contiguous */
+int sbicdma_misses = 0; /* number of DMA chains that were not contiguous */
+int sbicdma_saves = 0;
+
#define QPRINTF(a) if (sbic_debug > 1) printf a
-int sbic_debug = 0;
-int sync_debug = 0;
-int sbic_dma_debug = 0;
-int reselect_debug = 0;
-int report_sense = 0;
-int data_pointer_debug = 0;
-int sbic_timeout = 0;
-u_char debug_asr, debug_csr, timeout_active=0, routine;
-void sbictimeout __P((struct sbic_softc *dev));
+
+int sbic_debug = 0; /* Debug all chip related things */
+int sync_debug = 0; /* Debug all Synchronous Scsi related things */
+int reselect_debug = 0; /* Debug all reselection related things */
+int report_sense = 0; /* Always print Sense information */
+int data_pointer_debug = 0; /* Debug Data Pointer related things */
+
+void sbictimeout __P((struct sbic_softc *dev));
+
#else
-#define QPRINTF
+#define QPRINTF(a) /* */
#endif
+
/*
* default minphys routine for sbic based controllers
*/
void
sbic_minphys(bp)
- struct buf *bp;
+ struct buf *bp;
{
-
- /*
- * No max transfer at this level.
- */
- minphys(bp);
+ /*
+ * No max transfer at this level.
+ */
+ minphys(bp);
}
+
/*
* Save DMA pointers. Take into account partial transfer. Shut down DMA.
*/
void
-sbic_save_ptrs(dev, regs, target, lun)
- struct sbic_softc *dev;
- sbic_regmap_p regs;
- int target, lun;
+sbic_save_ptrs(dev)
+ struct sbic_softc *dev;
{
- int count, asr, csr, s;
- unsigned long ptr;
- char *vptr;
- struct sbic_acb* acb;
-
- extern vm_offset_t vm_first_phys;
-
- if( !dev->sc_cur ) return;
- if( !(dev->sc_flags & SBICF_INDMA) ) return; /* DMA not active */
-
- s = splbio();
-
- acb = dev->sc_nexus;
- count = -1;
- do {
- GET_SBIC_asr(regs, asr);
- if( asr & SBIC_ASR_DBR ) {
- printf("sbic_save_ptrs: asr %02x canceled!\n", asr);
- splx(s);
- return;
- }
- } while( asr & (SBIC_ASR_BSY|SBIC_ASR_CIP) );
-
- /* Save important state */
- /* must be done before dmastop */
- acb->sc_dmacmd = dev->sc_dmacmd;
- SBIC_TC_GET(regs, count);
-
- /* Shut down DMA ====CAREFUL==== */
- dev->sc_dmastop(dev);
- dev->sc_flags &= ~SBICF_INDMA;
- SBIC_TC_PUT(regs, 0);
+ sbic_regmap_p regs;
+ struct sbic_acb* acb;
+ int count,
+ asr,
+ s;
+
+ /*
+ * Only need to save pointers if DMA was active...
+ */
+ if ( dev->sc_cur == NULL || (dev->sc_flags & SBICF_INDMA) == 0 )
+ return;
+
+ regs = dev->sc_sbicp;
+
+ s = splbio();
+
+ /*
+ * Wait until WD chip is idle
+ */
+ do {
+ GET_SBIC_asr(regs, asr);
+ if( asr & SBIC_ASR_DBR ) {
+ printf("sbic_save_ptrs: asr %02x canceled!\n", asr);
+ splx(s);
+ return;
+ }
+ } while( asr & (SBIC_ASR_BSY|SBIC_ASR_CIP) );
+
+
+ /*
+ * Save important state.
+ * must be done before dmastop
+ */
+ acb = dev->sc_nexus;
+ acb->sc_dmacmd = dev->sc_dmacmd;
+
+ /*
+ * Fetch the residual count
+ */
+ SBIC_TC_GET(regs, count);
+
+ /*
+ * Shut down DMA
+ */
+ dev->sc_dmastop(dev);
+
+ /*
+ * No longer in DMA
+ */
+ dev->sc_flags &= ~SBICF_INDMA;
+
+ /*
+ * Ensure the WD chip is back in polled I/O mode, with nothing to
+ * transfer.
+ */
+ SBIC_TC_PUT(regs, 0);
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+ /*
+ * Update current count...
+ */
+ acb->sc_tcnt = count;
+
+ /*
+ * Work out how many bytes were actually transferred
+ */
+ count = dev->sc_tcnt - count;
+ dev->sc_tcnt = acb->sc_tcnt;
+
+ /*
+ * Fixup partial xfers
+ */
+ acb->sc_kv.dc_addr += count;
+ acb->sc_kv.dc_count -= count;
+ acb->sc_pa.dc_addr += count;
+ acb->sc_pa.dc_count -= count >> 1;
#ifdef DEBUG
- if(!count && sbic_debug) printf("%dcount0",target);
- if(data_pointer_debug == -1)
- printf("SBIC saving target %d data pointers from (%x,%x)%xASR:%02x",
- target, dev->sc_cur->dc_addr, dev->sc_cur->dc_count,
- acb->sc_dmacmd, asr);
+ if ( data_pointer_debug )
+ printf("save at (%x,%x):%x\n",
+ dev->sc_cur->dc_addr, dev->sc_cur->dc_count,count);
+ sbicdma_saves++;
#endif
- /* Fixup partial xfers */
- acb->sc_kv.dc_addr += (dev->sc_tcnt - count);
- acb->sc_kv.dc_count -= (dev->sc_tcnt - count);
- acb->sc_pa.dc_addr += (dev->sc_tcnt - count);
- acb->sc_pa.dc_count -= ((dev->sc_tcnt - count)>>1);
-
- acb->sc_tcnt = dev->sc_tcnt = count;
-#ifdef DEBUG
- if(data_pointer_debug)
- printf(" at (%x,%x):%x\n",
- dev->sc_cur->dc_addr, dev->sc_cur->dc_count,count);
- sbicdma_saves++;
-#endif
- splx(s);
+ splx(s);
}
/*
* DOES NOT RESTART DMA!!!
*/
-void sbic_load_ptrs(dev, regs, target, lun)
- struct sbic_softc *dev;
- sbic_regmap_p regs;
- int target, lun;
+void
+sbic_load_ptrs(dev)
+ struct sbic_softc *dev;
{
- int i, s, asr, count;
- char* vaddr, * paddr;
- struct sbic_acb *acb;
+ struct sbic_acb *acb = dev->sc_nexus;
+ int s;
- acb = dev->sc_nexus;
- if( !acb->sc_kv.dc_count )
- /* No data to xfer */
- return;
+ if ( acb->sc_kv.dc_count == 0 ) {
+ /*
+ * No data to xfer
+ */
+ return;
+ }
- s = splbio();
+ s = splbio();
- dev->sc_last = dev->sc_cur = &acb->sc_pa;
- dev->sc_tcnt = acb->sc_tcnt;
- dev->sc_dmacmd = acb->sc_dmacmd;
+ /*
+ * Reset the Scatter-Gather chain
+ */
+ dev->sc_last = dev->sc_cur = &acb->sc_pa;
-#ifdef DEBUG
- sbicdma_ops++;
-#endif
- if( !dev->sc_tcnt ) {
- /* sc_tcnt == 0 implies end of segment */
-
- /* do kvm to pa mappings */
- paddr = acb->sc_pa.dc_addr =
- (char *) kvtop(acb->sc_kv.dc_addr);
-
- vaddr = acb->sc_kv.dc_addr;
- count = acb->sc_kv.dc_count;
- for(count = (NBPG - ((int)vaddr & PGOFSET));
- count < acb->sc_kv.dc_count
- && (char*)kvtop(vaddr + count + 4) == paddr + count + 4;
- count += NBPG);
- /* If it's all contiguous... */
- if(count > acb->sc_kv.dc_count ) {
- count = acb->sc_kv.dc_count;
-#ifdef DEBUG
- sbicdma_hits++;
-#endif
- } else {
-#ifdef DEBUG
- sbicdma_misses++;
-#endif
- }
- acb->sc_tcnt = count;
- acb->sc_pa.dc_count = count >> 1;
+ /*
+ * Restore the Transfer Count and DMA specific data
+ */
+ dev->sc_tcnt = acb->sc_tcnt;
+ dev->sc_dmacmd = acb->sc_dmacmd;
#ifdef DEBUG
- if(data_pointer_debug)
- printf("DMA recalc:kv(%x,%x)pa(%x,%x)\n",
- acb->sc_kv.dc_addr,
- acb->sc_kv.dc_count,
- acb->sc_pa.dc_addr,
- acb->sc_tcnt);
-#endif
- }
- splx(s);
+ sbicdma_ops++;
+#endif
+
+ /*
+ * Need to fixup new segment?
+ */
+ if ( dev->sc_tcnt == 0 ) {
+ /*
+ * sc_tcnt == 0 implies end of segment
+ */
+ char *vaddr, *paddr;
+ int count;
+
+ /*
+ * do kvm to pa mappings
+ */
+ vaddr = acb->sc_kv.dc_addr;
+ paddr = acb->sc_pa.dc_addr = (char *) kvtop(vaddr);
+
+ for (count = (NBPG - ((int)vaddr & PGOFSET));
+ count < acb->sc_kv.dc_count &&
+ (char*)kvtop(vaddr + count + 4) == paddr + count + 4;
+ count += NBPG)
+ ; /* Do nothing */
+
+ /*
+ * If it's all contiguous...
+ */
+ if ( count > acb->sc_kv.dc_count ) {
+ count = acb->sc_kv.dc_count;
+#ifdef DEBUG
+ sbicdma_hits++;
+#endif
+ }
+#ifdef DEBUG
+ else
+ sbicdma_misses++;
+#endif
+
+ acb->sc_tcnt = count;
+ acb->sc_pa.dc_count = count >> 1;
+
#ifdef DEBUG
- if(data_pointer_debug)
- printf("SBIC restoring target %d data pointers at (%x,%x)%x\n",
- target, dev->sc_cur->dc_addr, dev->sc_cur->dc_count,
- dev->sc_dmacmd);
+ if ( data_pointer_debug )
+ printf("DMA recalc:kv(%x,%x)pa(%x,%x)\n", acb->sc_kv.dc_addr,
+ acb->sc_kv.dc_count,
+ acb->sc_pa.dc_addr,
+ acb->sc_tcnt);
#endif
+
+ }
+
+ splx(s);
}
/*
@@ -306,99 +363,107 @@ void sbic_load_ptrs(dev, regs, target, lun)
*/
int
sbic_scsicmd(xs)
- struct scsi_xfer *xs;
+ struct scsi_xfer *xs;
{
- struct sbic_acb *acb;
- struct sbic_softc *dev;
- struct scsi_link *slp;
- int flags, s, stat;
+ struct scsi_link *slp = xs->sc_link;
+ struct sbic_softc *dev = slp->adapter_softc;
+ struct sbic_acb *acb;
+ int flags = xs->flags,
+ s;
+
+ if ( flags & SCSI_DATA_UIO )
+ panic("sbic: scsi data uio requested");
- slp = xs->sc_link;
- dev = slp->adapter_softc;
- flags = xs->flags;
+ if ( dev->sc_nexus && (flags & SCSI_POLL) )
+ panic("sbic_scsicmd: busy");
- if (flags & SCSI_DATA_UIO)
- panic("sbic: scsi data uio requested");
+ if ( slp->target == slp->adapter_target )
+ return ESCAPE_NOT_SUPPORTED;
- if (dev->sc_nexus && flags & SCSI_POLL)
- panic("sbic_scsicmd: busy");
+ s = splbio();
- if (slp->target == slp->adapter_target)
- return ESCAPE_NOT_SUPPORTED;
+ if ( (acb = dev->free_list.tqh_first) != NULL )
+ TAILQ_REMOVE(&dev->free_list, acb, chain);
- s = splbio();
- acb = dev->free_list.tqh_first;
- if (acb)
- TAILQ_REMOVE(&dev->free_list, acb, chain);
- splx(s);
+ splx(s);
- if (acb == NULL) {
+ if ( acb == NULL ) {
#ifdef DEBUG
- printf("sbic_scsicmd: unable to queue request for target %d\n",
- slp->target);
+ printf("sbic_scsicmd: unable to queue request for target %d\n",
+ slp->target);
#ifdef DDB
- Debugger();
+ Debugger();
#endif
#endif
- xs->error = XS_DRIVER_STUFFUP;
- return(TRY_AGAIN_LATER);
- }
-
- acb->flags = ACB_ACTIVE;
- if (flags & SCSI_DATA_IN)
- acb->flags |= ACB_DATAIN;
- acb->xs = xs;
- bcopy(xs->cmd, &acb->cmd, xs->cmdlen);
- acb->clen = xs->cmdlen;
- acb->sc_kv.dc_addr = xs->data;
- acb->sc_kv.dc_count = xs->datalen;
- acb->pa_addr = xs->data ? (char *)kvtop(xs->data) : 0; /* XXXX check */
-
- if (flags & SCSI_POLL) {
- s = splbio();
- /*
- * This has major side effects -- it locks up the machine
- */
-
- dev->sc_flags |= SBICF_ICMD;
- do {
- while(dev->sc_nexus)
- sbicpoll(dev);
- dev->sc_nexus = acb;
- dev->sc_stat[0] = -1;
- dev->sc_xs = xs;
- dev->target = slp->target;
- dev->lun = slp->lun;
- stat = sbicicmd(dev, slp->target, slp->lun,
- &acb->cmd, acb->clen,
- acb->sc_kv.dc_addr, acb->sc_kv.dc_count);
- } while (dev->sc_nexus != acb);
- sbic_scsidone(acb, stat);
-
- splx(s);
- return(COMPLETE);
- }
-
- s = splbio();
- TAILQ_INSERT_TAIL(&dev->ready_list, acb, chain);
-
- if (dev->sc_nexus) {
- splx(s);
- return(SUCCESSFULLY_QUEUED);
- }
-
- /*
- * nothing is active, try to start it now.
- */
- sbic_sched(dev);
- splx(s);
-
-/* TODO: add sbic_poll to do SCSI_POLL operations */
-#if 0
- if (flags & SCSI_POLL)
- return(COMPLETE);
-#endif
- return(SUCCESSFULLY_QUEUED);
+ xs->error = XS_DRIVER_STUFFUP;
+
+ return(TRY_AGAIN_LATER);
+ }
+
+ if ( flags & SCSI_DATA_IN )
+ acb->flags = ACB_ACTIVE | ACB_DATAIN;
+ else
+ acb->flags = ACB_ACTIVE;
+
+ acb->xs = xs;
+ acb->clen = xs->cmdlen;
+ acb->sc_kv.dc_addr = xs->data;
+ acb->sc_kv.dc_count = xs->datalen;
+ acb->pa_addr = xs->data ? (char *)kvtop(xs->data) : 0;
+ bcopy(xs->cmd, &acb->cmd, xs->cmdlen);
+
+ if ( flags & SCSI_POLL ) {
+ /*
+ * This has major side effects -- it locks up the machine
+ */
+ int stat;
+
+ s = splbio();
+
+ dev->sc_flags |= SBICF_ICMD;
+
+ do {
+ /*
+ * If we already had a nexus, while away the time until idle...
+ * This is likely only to happen if a reselection occurs between
+ * here and our earlier check for ICMD && sc_nexus (which would
+ * have resulted in a panic() had it been true).
+ */
+ while ( dev->sc_nexus )
+ sbicpoll(dev);
+
+ /*
+ * Fix up the new nexus
+ */
+ dev->sc_nexus = acb;
+ dev->sc_xs = xs;
+ dev->target = slp->target;
+ dev->lun = slp->lun;
+
+ stat = sbicicmd(dev, &acb->cmd, acb->clen,
+ acb->sc_kv.dc_addr, acb->sc_kv.dc_count);
+
+ } while ( dev->sc_nexus != acb );
+
+ sbic_scsidone(acb, stat);
+
+ splx(s);
+
+ return(COMPLETE);
+ }
+
+ s = splbio();
+ TAILQ_INSERT_TAIL(&dev->ready_list, acb, chain);
+
+ /*
+ * If nothing is active, try to start it now.
+ */
+ if ( dev->sc_nexus == NULL )
+ sbic_sched(dev);
+
+ splx(s);
+
+ return(SUCCESSFULLY_QUEUED);
}
/*
@@ -406,846 +471,827 @@ sbic_scsicmd(xs)
*/
void
sbic_sched(dev)
- struct sbic_softc *dev;
+ struct sbic_softc *dev;
{
- struct scsi_xfer *xs;
- struct scsi_link *slp;
- struct sbic_acb *acb;
- int flags, /*phase,*/ stat, i;
-
- if (dev->sc_nexus)
- return; /* a command is current active */
-
- for (acb = dev->ready_list.tqh_first; acb; acb = acb->chain.tqe_next) {
- slp = acb->xs->sc_link;
- i = slp->target;
- if (!(dev->sc_tinfo[i].lubusy & (1 << slp->lun))) {
- struct sbic_tinfo *ti = &dev->sc_tinfo[i];
-
- TAILQ_REMOVE(&dev->ready_list, acb, chain);
- dev->sc_nexus = acb;
- slp = acb->xs->sc_link;
- ti = &dev->sc_tinfo[slp->target];
- ti->lubusy |= (1 << slp->lun);
- acb->sc_pa.dc_addr = acb->pa_addr; /* XXXX check */
- break;
- }
- }
-
- if (acb == NULL)
- return; /* did not find an available command */
-
- dev->sc_xs = xs = acb->xs;
- slp = xs->sc_link;
- flags = xs->flags;
-
- if (flags & SCSI_RESET)
- sbicreset(dev);
+ struct scsi_xfer *xs;
+ struct scsi_link *slp = NULL; /* Gag the compiler */
+ struct sbic_acb *acb;
+ int flags,
+ stat;
+
+ /*
+ * XXXSCW
+ * I'll keep this test here, even though I can't see any obvious way
+ * in which sbic_sched() could be called with sc_nexus non NULL
+ */
+ if ( dev->sc_nexus )
+ return; /* a command is current active */
+
+ /*
+ * Loop through the ready list looking for work to do...
+ */
+ for (acb = dev->ready_list.tqh_first; acb; acb = acb->chain.tqe_next) {
+ int i, j;
+
+ slp = acb->xs->sc_link;
+ i = slp->target;
+ j = 1 << slp->lun;
+
+ /*
+ * We've found a potential command, but is the target/lun busy?
+ */
+ if ( (dev->sc_tinfo[i].lubusy & j) == 0 ) {
+ /*
+ * Nope, it's not busy, so we can use it.
+ */
+ dev->sc_tinfo[i].lubusy |= j;
+ TAILQ_REMOVE(&dev->ready_list, acb, chain);
+ dev->sc_nexus = acb;
+ acb->sc_pa.dc_addr = acb->pa_addr; /* XXXX check */
+ break;
+ }
+ }
+
+ if ( acb == NULL ) {
+ QPRINTF(("sbicsched: no work\n"));
+ return; /* did not find an available command */
+ }
#ifdef DEBUG
- if( data_pointer_debug > 1 )
- printf("sbic_sched(%d,%d)\n",slp->target,slp->lun);
+ if ( data_pointer_debug > 1 )
+ printf("sbic_sched(%d,%d)\n", slp->target, slp->lun);
#endif
- dev->sc_stat[0] = -1;
- dev->target = slp->target;
- dev->lun = slp->lun;
- if ( flags & SCSI_POLL || ( !sbic_parallel_operations
- && (/*phase == STATUS_PHASE ||*/
- sbicdmaok(dev, xs) == 0) ) )
- stat = sbicicmd(dev, slp->target, slp->lun, &acb->cmd,
- acb->clen, acb->sc_kv.dc_addr, acb->sc_kv.dc_count);
- else if (sbicgo(dev, xs) == 0)
- return;
- else
- stat = dev->sc_stat[0];
-
- sbic_scsidone(acb, stat);
+
+ dev->sc_xs = xs = acb->xs;
+ flags = xs->flags;
+
+ if ( flags & SCSI_RESET )
+ sbicreset(dev);
+
+ dev->sc_stat[0] = -1;
+ dev->target = slp->target;
+ dev->lun = slp->lun;
+
+ if ( flags & SCSI_POLL || (!sbic_parallel_operations &&
+ (sbicdmaok(dev, xs) == 0)) )
+ stat = sbicicmd(dev, &acb->cmd, acb->clen,
+ acb->sc_kv.dc_addr, acb->sc_kv.dc_count);
+ else
+ if ( sbicgo(dev, xs) == 0 )
+ return;
+ else
+ stat = dev->sc_stat[0];
+
+ sbic_scsidone(acb, stat);
}
void
sbic_scsidone(acb, stat)
- struct sbic_acb *acb;
- int stat;
+ struct sbic_acb *acb;
+ int stat;
{
- struct scsi_xfer *xs;
- struct scsi_link *slp;
- struct sbic_softc *dev;
- int s, dosched = 0;
-
- xs = acb->xs;
- slp = xs->sc_link;
- dev = slp->adapter_softc;
+ struct scsi_xfer *xs = acb->xs;
+ struct scsi_link *slp = xs->sc_link;
+ struct sbic_softc *dev = slp->adapter_softc;
+ int dosched = 0;
+
#ifdef DIAGNOSTIC
- if (acb == NULL || xs == NULL) {
- printf("sbic_scsidone -- (%d,%d) no scsi_xfer\n",
- dev->target, dev->lun);
+ if ( acb == NULL || xs == NULL ) {
+ printf("sbic_scsidone -- (%d,%d) no scsi_xfer\n", dev->target, dev->lun);
#ifdef DDB
- Debugger();
-#endif
- return;
- }
+ Debugger();
#endif
-#if 1
- if (((struct device *)(slp->device_softc))->dv_unit < dk_ndrive)
- ++dk_xfer[((struct device *)(slp->device_softc))->dv_unit];
+ return;
+ }
#endif
- /*
- * is this right?
- */
- xs->status = stat;
+
+ if ( slp->device_softc &&
+ ((struct device *)(slp->device_softc))->dv_unit < dk_ndrive)
+ ++dk_xfer[((struct device *)(slp->device_softc))->dv_unit];
+
+ /*
+ * is this right?
+ */
+ xs->status = stat;
#ifdef DEBUG
- if( data_pointer_debug > 1 )
- printf("scsidone: (%d,%d)->(%d,%d)%02x\n",
- slp->target, slp->lun,
- dev->target, dev->lun, stat);
- if( xs->sc_link->target == dev->sc_link.adapter_target )
- panic("target == hostid");
+ if ( data_pointer_debug > 1 )
+ printf("scsidone: (%d,%d)->(%d,%d)%02x\n", slp->target, slp->lun,
+ dev->target, dev->lun, stat);
+
+ if ( xs->sc_link->target == dev->sc_link.adapter_target )
+ panic("target == hostid");
#endif
- if (xs->error == XS_NOERROR && !(acb->flags & ACB_CHKSENSE)) {
- if (stat == SCSI_CHECK) {
- /* Schedule a REQUEST SENSE */
- struct scsi_sense *ss = (void *)&acb->cmd;
+ if ( xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE) == 0 ) {
+
+ if ( stat == SCSI_CHECK ) {
+ /*
+ * Schedule a REQUEST SENSE
+ */
+ struct scsi_sense *ss = (void *)&acb->cmd;
+
#ifdef DEBUG
- if (report_sense)
- printf("sbic_scsidone: autosense %02x targ %d lun %d",
- acb->cmd.opcode, slp->target, slp->lun);
+ if ( report_sense )
+ printf("sbic_scsidone: autosense %02x targ %d lun %d",
+ acb->cmd.opcode, slp->target, slp->lun);
#endif
- bzero(ss, sizeof(*ss));
- ss->opcode = REQUEST_SENSE;
- ss->byte2 = slp->lun << 5;
- ss->length = sizeof(struct scsi_sense_data);
- acb->clen = sizeof(*ss);
- acb->sc_kv.dc_addr = (char *)&xs->sense;
- acb->sc_kv.dc_count = sizeof(struct scsi_sense_data);
- acb->pa_addr = (char *)kvtop(&xs->sense); /* XXX check */
- acb->flags = ACB_ACTIVE | ACB_CHKSENSE | ACB_DATAIN;
- TAILQ_INSERT_HEAD(&dev->ready_list, acb, chain);
- dev->sc_tinfo[slp->target].lubusy &=
- ~(1 << slp->lun);
- dev->sc_tinfo[slp->target].senses++;
- if (dev->sc_nexus == acb) {
- dev->sc_nexus = NULL;
- sbic_sched(dev);
- }
- return;
- }
- }
- if (xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE)) {
- xs->error = XS_SENSE;
+
+ bzero(ss, sizeof(*ss));
+
+ ss->opcode = REQUEST_SENSE;
+ ss->byte2 = slp->lun << 5;
+ ss->length = sizeof(struct scsi_sense_data);
+
+ acb->clen = sizeof(*ss);
+ acb->sc_kv.dc_addr = (char *)&xs->sense;
+ acb->sc_kv.dc_count = sizeof(struct scsi_sense_data);
+ acb->pa_addr = (char *)kvtop(&xs->sense); /* XXX check */
+ acb->flags = ACB_ACTIVE | ACB_CHKSENSE | ACB_DATAIN;
+
+ TAILQ_INSERT_HEAD(&dev->ready_list, acb, chain);
+
+ dev->sc_tinfo[slp->target].lubusy &= ~(1 << slp->lun);
+ dev->sc_tinfo[slp->target].senses++;
+
+ if ( dev->sc_nexus == acb ) {
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+ sbic_sched(dev);
+ }
+ return;
+ }
+ }
+
+ if ( xs->error == XS_NOERROR && (acb->flags & ACB_CHKSENSE) != 0 ) {
+
+ xs->error = XS_SENSE;
+
#ifdef DEBUG
- if (report_sense)
- printf(" => %02x %02x\n", xs->sense.extended_flags,
- xs->sense.extended_extra_bytes[3]);
-#endif
- } else {
- xs->resid = 0; /* XXXX */
- }
-#if whataboutthisone
- case SCSI_BUSY:
- xs->error = XS_BUSY;
- break;
+ if (report_sense)
+ printf(" => %02x %02x\n", xs->sense.flags,
+ xs->sense.extra_bytes[3]);
#endif
- xs->flags |= ITSDONE;
-
- /*
- * Remove the ACB from whatever queue it's on. We have to do a bit of
- * a hack to figure out which queue it's on. Note that it is *not*
- * necessary to cdr down the ready queue, but we must cdr down the
- * nexus queue and see if it's there, so we can mark the unit as no
- * longer busy. This code is sickening, but it works.
- */
- if (acb == dev->sc_nexus) {
- dev->sc_nexus = NULL;
- dev->sc_tinfo[slp->target].lubusy &= ~(1<<slp->lun);
- if (dev->ready_list.tqh_first)
- dosched = 1; /* start next command */
- } else if (dev->ready_list.tqh_last == &acb->chain.tqe_next) {
- TAILQ_REMOVE(&dev->ready_list, acb, chain);
- } else {
- register struct sbic_acb *acb2;
- for (acb2 = dev->nexus_list.tqh_first; acb2;
- acb2 = acb2->chain.tqe_next)
- if (acb2 == acb) {
- TAILQ_REMOVE(&dev->nexus_list, acb, chain);
- dev->sc_tinfo[slp->target].lubusy
- &= ~(1<<slp->lun);
- break;
- }
- if (acb2)
- ;
- else if (acb->chain.tqe_next) {
- TAILQ_REMOVE(&dev->ready_list, acb, chain);
- } else {
- printf("%s: can't find matching acb\n",
- dev->sc_dev.dv_xname);
+
+ } else {
+ xs->resid = 0; /* XXXX */
+ }
+
+ xs->flags |= ITSDONE;
+
+ /*
+ * Remove the ACB from whatever queue it's on. We have to do a bit of
+ * a hack to figure out which queue it's on. Note that it is *not*
+ * necessary to cdr down the ready queue, but we must cdr down the
+ * nexus queue and see if it's there, so we can mark the unit as no
+ * longer busy. This code is sickening, but it works.
+ */
+ if ( acb == dev->sc_nexus ) {
+
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+
+ dev->sc_tinfo[slp->target].lubusy &= ~(1 << slp->lun);
+
+ if ( dev->ready_list.tqh_first )
+ dosched = 1; /* start next command */
+
+ } else
+ if ( dev->ready_list.tqh_last == &acb->chain.tqe_next ) {
+
+ TAILQ_REMOVE(&dev->ready_list, acb, chain);
+
+ } else {
+
+ register struct sbic_acb *a;
+
+ for (a = dev->nexus_list.tqh_first; a; a = a->chain.tqe_next) {
+ if ( a == acb ) {
+ TAILQ_REMOVE(&dev->nexus_list, acb, chain);
+ dev->sc_tinfo[slp->target].lubusy &= ~(1 << slp->lun);
+ break;
+ }
+ }
+
+ if ( a )
+ ;
+ else if ( acb->chain.tqe_next ) {
+ TAILQ_REMOVE(&dev->ready_list, acb, chain);
+ } else {
+ printf("%s: can't find matching acb\n", dev->sc_dev.dv_xname);
#ifdef DDB
- Debugger();
+ Debugger();
#endif
- }
- }
- /* Put it on the free list. */
- acb->flags = ACB_FREE;
- TAILQ_INSERT_HEAD(&dev->free_list, acb, chain);
+ }
+ }
+
+ /*
+ * Put it on the free list.
+ */
+ acb->flags = ACB_FREE;
+ TAILQ_INSERT_HEAD(&dev->free_list, acb, chain);
- dev->sc_tinfo[slp->target].cmds++;
+ dev->sc_tinfo[slp->target].cmds++;
- scsi_done(xs);
+ scsi_done(xs);
- if (dosched)
- sbic_sched(dev);
+ if ( dosched )
+ sbic_sched(dev);
}
int
sbicdmaok(dev, xs)
- struct sbic_softc *dev;
- struct scsi_xfer *xs;
+ struct sbic_softc *dev;
+ struct scsi_xfer *xs;
{
- if (sbic_no_dma || xs->datalen & 0x1 || (u_int)xs->data & 0x3)
- return(0);
- /*
- * controller supports dma to any addresses?
- */
- else if ((dev->sc_flags & SBICF_BADDMA) == 0)
- return(1);
- /*
- * this address is ok for dma?
- */
- else if (sbiccheckdmap(xs->data, xs->datalen, dev->sc_dmamask) == 0)
- return(1);
-#if 0
- /*
- * we have a bounce buffer?
- */
- else if (dev->sc_tinfo[xs->sc_link->target].bounce)
- return(1);
- /*
- * try to get one
- */
- else if (dev->sc_tinfo[xs->sc_link->target].bounce
- = (char *)alloc_z2mem(MAXPHYS)) {
- if (isztwomem(dev->sc_tinfo[xs->sc_link->target].bounce))
- printf("alloc ZII target %d bounce pa 0x%x\n",
- xs->sc_link->target,
- kvtop(dev->sc_tinfo[xs->sc_link->target].bounce));
- else if (dev->sc_tinfo[xs->sc_link->target].bounce)
- printf("alloc CHIP target %d bounce pa 0x%x\n",
- xs->sc_link->target,
- PREP_DMA_MEM(dev->sc_tinfo[xs->sc_link->target].bounce));
- return(1);
- }
-#endif
-
- return(0);
+ if ( sbic_no_dma || xs->datalen & 0x03 || (int)xs->data & 0x03)
+ return(0);
+
+ /*
+ * controller supports dma to any addresses?
+ */
+ if ( (dev->sc_flags & SBICF_BADDMA) == 0 )
+ return(1);
+
+ /*
+ * this address is ok for dma?
+ */
+ if ( sbiccheckdmap(xs->data, xs->datalen, dev->sc_dmamask) == 0 )
+ return(1);
+
+ return(0);
}
-
int
sbicwait(regs, until, timeo, line)
- sbic_regmap_p regs;
- char until;
- int timeo;
- int line;
-{
- u_char val;
- int csr;
-
- if (timeo == 0)
- timeo = 10000; /* some large value.. */
-
- GET_SBIC_asr(regs,val);
- while ((val & until) == 0) {
- if (timeo-- == 0) {
- GET_SBIC_csr(regs, csr);
- printf("sbicwait TIMEO @%d with asr=x%x csr=x%x\n",
- line, val, csr);
-#if defined(DDB) && defined(DEBUG)
- Debugger();
-#endif
- return(val); /* Maybe I should abort */
- break;
- }
- DELAY(1);
- GET_SBIC_asr(regs,val);
- }
- return(val);
-}
-
-int
-sbicabort(dev, regs, where)
- struct sbic_softc *dev;
- sbic_regmap_p regs;
- char *where;
+ sbic_regmap_p regs;
+ u_char until;
+ int timeo;
+ int line;
{
- u_char csr, asr;
+ u_char val;
- GET_SBIC_csr(regs, csr);
- GET_SBIC_asr(regs, asr);
+ if ( timeo == 0 )
+ timeo = 1000000; /* some large value.. */
- printf ("%s: abort %s: csr = 0x%02x, asr = 0x%02x\n",
- dev->sc_dev.dv_xname, where, csr, asr);
+ GET_SBIC_asr(regs, val);
+ while ( (val & until) == 0 ) {
-#if 0
- /* Clean up running command */
- if (dev->sc_nexus != NULL) {
- dev->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
- sbic_scsidone(dev->sc_nexus, dev->sc_stat[0]);
- }
- while (acb = dev->nexus_list.tqh_first) {
- acb->xs->error = XS_DRIVER_STUFFUP;
- sbic_scsidone(acb, -1 /*acb->stat[0]*/);
- }
+ if ( timeo-- == 0 ) {
+ int csr;
+ GET_SBIC_csr(regs, csr);
+ printf("sbicwait TIMEO @%d with asr=x%x csr=x%x\n", line, val, csr);
+#if defined(DDB) && defined(DEBUG)
+ Debugger();
#endif
+ return(val); /* Maybe I should abort */
+ break;
+ }
+
+ DELAY(1);
+ GET_SBIC_asr(regs, val);
+ }
+
+ return(val);
+}
- /* Clean up chip itself */
- if (dev->sc_flags & SBICF_SELECTED) {
- while( asr & SBIC_ASR_DBR ) {
- /* sbic is jammed w/data. need to clear it */
- /* But we don't know what direction it needs to go */
- GET_SBIC_data(regs, asr);
- printf("%s: abort %s: clearing data buffer 0x%02x\n",
- dev->sc_dev.dv_xname, where, asr);
- GET_SBIC_asr(regs, asr);
- if( asr & SBIC_ASR_DBR ) /* Not the read direction, then */
- SET_SBIC_data(regs, asr);
- GET_SBIC_asr(regs, asr);
- }
- WAIT_CIP(regs);
- SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
- WAIT_CIP(regs);
-
- GET_SBIC_asr(regs, asr);
- if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) {
- /* ok, get more drastic.. */
-
- sbicreset(dev);
- dev->sc_flags &= ~SBICF_SELECTED;
- return -1;
- }
- SET_SBIC_cmd(regs, SBIC_CMD_DISC);
-
- do {
- SBIC_WAIT (regs, SBIC_ASR_INT, 0);
- GET_SBIC_csr (regs, csr);
- } while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
- && (csr != SBIC_CSR_CMD_INVALID));
-
- /* lets just hope it worked.. */
- dev->sc_flags &= ~SBICF_SELECTED;
- }
- return -1;
+int
+sbicabort(dev, where)
+ struct sbic_softc *dev;
+ char *where;
+{
+ sbic_regmap_p regs = dev->sc_sbicp;
+ u_char csr,
+ asr;
+
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr(regs, csr);
+
+ printf ("%s: abort %s: csr = 0x%02x, asr = 0x%02x\n",
+ dev->sc_dev.dv_xname, where, csr, asr);
+
+ /*
+ * Clean up chip itself
+ */
+ if ( dev->sc_flags & SBICF_SELECTED ) {
+
+ while ( asr & SBIC_ASR_DBR ) {
+ /*
+ * sbic is jammed w/data. need to clear it
+ * But we don't know what direction it needs to go
+ */
+ GET_SBIC_data(regs, asr);
+ printf("%s: abort %s: clearing data buffer 0x%02x\n",
+ dev->sc_dev.dv_xname, where, asr);
+ GET_SBIC_asr(regs, asr);
+ if ( asr & SBIC_ASR_DBR ) /* Not the read direction, then */
+ SET_SBIC_data(regs, asr);
+ GET_SBIC_asr(regs, asr);
+ }
+
+ WAIT_CIP(regs);
+
+ printf("%s: sbicabort - sending ABORT command\n", dev->sc_dev.dv_xname);
+ SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
+ WAIT_CIP(regs);
+
+ GET_SBIC_asr(regs, asr);
+
+ if ( asr & (SBIC_ASR_BSY|SBIC_ASR_LCI) ) {
+ /*
+ * ok, get more drastic..
+ */
+ printf("%s: sbicabort - asr %x, trying to reset\n",
+ dev->sc_dev.dv_xname, asr);
+ sbicreset(dev);
+ dev->sc_flags &= ~SBICF_SELECTED;
+ return -1;
+ }
+
+ printf("%s: sbicabort - sending DISC command\n", dev->sc_dev.dv_xname);
+ SET_SBIC_cmd(regs, SBIC_CMD_DISC);
+
+ do {
+ SBIC_WAIT (regs, SBIC_ASR_INT, 0);
+ GET_SBIC_asr(regs, asr);
+ GET_SBIC_csr (regs, csr);
+ QPRINTF(("csr: 0x%02x, asr: 0x%02x\n", csr, asr));
+ } while ( (csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1) &&
+ (csr != SBIC_CSR_CMD_INVALID) );
+
+ /*
+ * lets just hope it worked..
+ */
+ dev->sc_flags &= ~SBICF_SELECTED;
+ }
+
+ return -1;
}
/*
* Initialize driver-private structures
*/
-
void
sbicinit(dev)
- struct sbic_softc *dev;
+ struct sbic_softc *dev;
{
- sbic_regmap_p regs;
- u_int my_id, i, s;
- u_char csr;
- struct sbic_acb *acb;
-
- regs = dev->sc_sbicp;
-
- if ((dev->sc_flags & SBICF_ALIVE) == 0) {
- TAILQ_INIT(&dev->ready_list);
- TAILQ_INIT(&dev->nexus_list);
- TAILQ_INIT(&dev->free_list);
- dev->sc_nexus = NULL;
- dev->sc_xs = NULL;
- acb = dev->sc_acb;
- bzero(acb, sizeof(dev->sc_acb));
- for (i = 0; i < sizeof(dev->sc_acb) / sizeof(*acb); i++) {
- TAILQ_INSERT_TAIL(&dev->free_list, acb, chain);
- acb++;
- }
- bzero(dev->sc_tinfo, sizeof(dev->sc_tinfo));
- } else panic("sbic: reinitializing driver!");
-
- dev->sc_flags |= SBICF_ALIVE;
- dev->sc_flags &= ~SBICF_SELECTED;
-
- sbicreset(dev);
-}
+ u_int i;
-void
-sbicreset(dev)
- struct sbic_softc *dev;
-{
- sbic_regmap_p regs;
- u_int my_id, i, s;
- u_char csr;
- struct sbic_acb *acb;
+ extern u_long scsi_nosync;
+ extern int shift_nosync;
- regs = dev->sc_sbicp;
-#if 0
- if (dev->sc_flags & SBICF_ALIVE) {
- SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
- WAIT_CIP(regs);
- }
-#else
- SET_SBIC_cmd(regs, SBIC_CMD_ABORT);
- WAIT_CIP(regs);
-#endif
- s = splbio();
- my_id = dev->sc_link.adapter_target & SBIC_ID_MASK;
-
- /* Enable advanced mode */
- my_id |= SBIC_ID_EAF /*| SBIC_ID_EHP*/ ;
- SET_SBIC_myid(regs, my_id);
-
- /*
- * Disable interrupts (in dmainit) then reset the chip
- */
- SET_SBIC_cmd(regs, SBIC_CMD_RESET);
- DELAY(25);
- SBIC_WAIT(regs, SBIC_ASR_INT, 0);
- GET_SBIC_csr(regs, csr); /* clears interrupt also */
-
- if (dev->sc_clkfreq < 110)
- my_id |= SBIC_ID_FS_8_10;
- else if (dev->sc_clkfreq < 160)
- my_id |= SBIC_ID_FS_12_15;
- else if (dev->sc_clkfreq < 210)
- my_id |= SBIC_ID_FS_16_20;
-
- SET_SBIC_myid(regs, my_id);
-
- /*
- * Set up various chip parameters
- */
- SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI /* | SBIC_CTL_HSP */
- | SBIC_MACHINE_DMA_MODE);
- /*
- * don't allow (re)selection (SBIC_RID_ES)
- * until we can handle target mode!!
- */
- SET_SBIC_rselid(regs, SBIC_RID_ER);
- SET_SBIC_syn(regs, 0); /* asynch for now */
-
- /*
- * anything else was zeroed by reset
- */
- splx(s);
+ if ( (dev->sc_flags & SBICF_ALIVE) == 0 ) {
-#if 0
- if ((dev->sc_flags & SBICF_ALIVE) == 0) {
- TAILQ_INIT(&dev->ready_list);
- TAILQ_INIT(&dev->nexus_list);
- TAILQ_INIT(&dev->free_list);
- dev->sc_nexus = NULL;
- dev->sc_xs = NULL;
- acb = dev->sc_acb;
- bzero(acb, sizeof(dev->sc_acb));
- for (i = 0; i < sizeof(dev->sc_acb) / sizeof(*acb); i++) {
- TAILQ_INSERT_TAIL(&dev->free_list, acb, chain);
- acb++;
- }
- bzero(dev->sc_tinfo, sizeof(dev->sc_tinfo));
- } else {
- if (dev->sc_nexus != NULL) {
- dev->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
- sbic_scsidone(dev->sc_nexus, dev->sc_stat[0]);
- }
- while (acb = dev->nexus_list.tqh_first) {
- acb->xs->error = XS_DRIVER_STUFFUP;
- sbic_scsidone(acb, -1 /*acb->stat[0]*/);
- }
- }
-
- dev->sc_flags |= SBICF_ALIVE;
-#endif
- dev->sc_flags &= ~SBICF_SELECTED;
-}
+ struct sbic_acb *acb;
-void
-sbicerror(dev, regs, csr)
- struct sbic_softc *dev;
- sbic_regmap_p regs;
- u_char csr;
-{
- struct scsi_xfer *xs;
+ TAILQ_INIT(&dev->ready_list);
+ TAILQ_INIT(&dev->nexus_list);
+ TAILQ_INIT(&dev->free_list);
- xs = dev->sc_xs;
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
-#ifdef DIAGNOSTIC
- if (xs == NULL)
- panic("sbicerror");
-#endif
- if (xs->flags & SCSI_SILENT)
- return;
+ acb = dev->sc_acb;
+ bzero(acb, sizeof(dev->sc_acb));
- printf("%s: ", dev->sc_dev.dv_xname);
- printf("csr == 0x%02x\n", csr); /* XXX */
-}
+ for (i = 0; i < sizeof(dev->sc_acb) / sizeof(*acb); i++) {
+ TAILQ_INSERT_TAIL(&dev->free_list, acb, chain);
+ acb++;
+ }
-/*
- * select the bus, return when selected or error.
- */
-int
-sbicselectbus(dev, regs, target, lun, our_addr)
- struct sbic_softc *dev;
- sbic_regmap_p regs;
- u_char target, lun, our_addr;
-{
- u_char asr, csr, id;
+ bzero(dev->sc_tinfo, sizeof(dev->sc_tinfo));
- QPRINTF(("sbicselectbus %d\n", target));
+#ifdef DEBUG
+ /*
+ * make sure timeout is really not needed
+ */
+ timeout((void *)sbictimeout, dev, 30 * hz);
+#endif
- /*
- * if we're already selected, return (XXXX panic maybe?)
- */
- if (dev->sc_flags & SBICF_SELECTED)
- return(1);
+ } else
+ panic("sbic: reinitializing driver!");
- SET_SBIC_rselid (regs, 0);
-#if 0
- GET_SBIC_asr(regs, asr);
- if( asr & (SBIC_ASR_INT|SBIC_ASR_BSY) ) {
- /* This means we got ourselves reselected upon */
-/* printf("sbicselectbus: weird asr %02x\n", asr);*/
-#ifdef DDB
-/* Debugger();*/
-#endif
- SET_SBIC_rselid (regs, SBIC_RID_ER);
- return 1;
- }
-#endif
- /*
- * issue select
- */
- SBIC_TC_PUT(regs, 0);
- SET_SBIC_selid(regs, target);
- SET_SBIC_timeo(regs, SBIC_TIMEOUT(250,dev->sc_clkfreq));
-
- /*
- * set sync or async
- */
- if (dev->sc_sync[target].state == SYNC_DONE)
- SET_SBIC_syn(regs, SBIC_SYN (dev->sc_sync[target].offset,
- dev->sc_sync[target].period));
- else
- SET_SBIC_syn(regs, SBIC_SYN (0, sbic_min_period));
-
- GET_SBIC_asr(regs, asr);
- if( asr & (SBIC_ASR_INT|SBIC_ASR_BSY) ) {
- /* This means we got ourselves reselected upon */
-/* printf("sbicselectbus: INT/BSY asr %02x\n", asr);*/
-#ifdef DDB
-/* Debugger();*/
-#endif
- return 1;
- }
+ dev->sc_flags |= SBICF_ALIVE;
+ dev->sc_flags &= ~SBICF_SELECTED;
- SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN);
+ /*
+ * initialize inhibit array
+ */
+ if ( scsi_nosync ) {
- /*
- * wait for select (merged from seperate function may need
- * cleanup)
- */
- WAIT_CIP(regs);
-#if 0
- GET_SBIC_asr(regs, asr);
- if( asr & SBIC_ASR_LCI ) {
- /* This means we got ourselves reselected upon */
-#ifdef DEBUG
- if (reselect_debug)
- printf("sbicselectbus: LCI asr %02x\n", asr);
-/* Debugger();*/
-#endif
- return 1;
- }
-#endif
- do {
- asr = SBIC_WAIT(regs, SBIC_ASR_INT | SBIC_ASR_LCI, 0);
- if (asr & SBIC_ASR_LCI) {
-#ifdef DEBUG
- if (reselect_debug)
- printf("sbicselectbus: late LCI asr %02x\n", asr);
-#endif
- return 1;
- }
- GET_SBIC_csr (regs, csr);
- QPRINTF(("%02x ", csr));
- if( csr == SBIC_CSR_RSLT_NI || csr == SBIC_CSR_RSLT_IFY) {
-#ifdef DEBUG
- if( reselect_debug || 1 )
- printf("sbicselectbus: reselected asr %02x\n", asr);
-#endif
- /* We need to handle this now so we don't lock up later */
- sbicnextstate(dev, csr, asr);
- return 1;
- }
- if( csr == SBIC_CSR_SLT || csr == SBIC_CSR_SLT_ATN) {
- panic("sbicselectbus: target issued select!");
- return 1;
- }
- } while (csr != (SBIC_CSR_MIS_2|MESG_OUT_PHASE)
- && csr != (SBIC_CSR_MIS_2|CMD_PHASE) && csr != SBIC_CSR_SEL_TIMEO);
-
- /* Enable (or not) reselection */
- if( (dev->sc_xs->flags & SCSI_POLL
- || (dev->sc_flags & SBICF_ICMD)
- || !sbic_enable_reselect)
- && dev->nexus_list.tqh_first == NULL )
- SET_SBIC_rselid (regs, 0);
- else
- SET_SBIC_rselid (regs, SBIC_RID_ER);
-
- if (csr == (SBIC_CSR_MIS_2|CMD_PHASE)) {
- dev->sc_flags |= SBICF_SELECTED; /* device ignored ATN */
- GET_SBIC_selid(regs, id);
- dev->target = id;
- GET_SBIC_tlun(regs,dev->lun);
- if( dev->lun & SBIC_TLUN_VALID )
- dev->lun &= SBIC_TLUN_MASK;
- else
- dev->lun = lun;
- } else if (csr == (SBIC_CSR_MIS_2|MESG_OUT_PHASE)) {
- /*
- * Send identify message
- * (SCSI-2 requires an identify msg (?))
- */
- GET_SBIC_selid(regs, id);
- dev->target = id;
- GET_SBIC_tlun(regs,dev->lun);
- if( dev->lun & SBIC_TLUN_VALID )
- dev->lun &= SBIC_TLUN_MASK;
- else
- dev->lun = lun;
- /*
- * handle drives that don't want to be asked
- * whether to go sync at all.
- */
- if (sbic_inhibit_sync && dev->sc_sync[id].state == SYNC_START) {
-#ifdef DEBUG
- if (sync_debug)
- printf("Forcing target %d asynchronous.\n", id);
-#endif
- dev->sc_sync[id].offset = 0;
- dev->sc_sync[id].period = sbic_min_period;
- dev->sc_sync[id].state = SYNC_DONE;
- }
-
-
- if (dev->sc_sync[id].state != SYNC_START){
- if( dev->sc_xs->flags & SCSI_POLL
- || (dev->sc_flags & SBICF_ICMD)
- || !sbic_enable_reselect )
- SEND_BYTE (regs, MSG_IDENTIFY | lun);
- else
- SEND_BYTE (regs, MSG_IDENTIFY_DR | lun);
- } else {
- /*
- * try to initiate a sync transfer.
- * So compose the sync message we're going
- * to send to the target
- */
+ u_int inhibit_sync = (scsi_nosync >> shift_nosync) & 0xff;
-#ifdef DEBUG
- if (sync_debug)
- printf("Sending sync request to target %d ... ",
- id);
-#endif
- /*
- * setup scsi message sync message request
- */
- dev->sc_msg[0] = MSG_IDENTIFY | lun;
- dev->sc_msg[1] = MSG_EXT_MESSAGE;
- dev->sc_msg[2] = 3;
- dev->sc_msg[3] = MSG_SYNC_REQ;
- dev->sc_msg[4] = sbictoscsiperiod(dev, regs,
- sbic_min_period);
- dev->sc_msg[5] = sbic_max_offset;
-
- if (sbicxfstart(regs, 6, MESG_OUT_PHASE, sbic_cmd_wait))
- sbicxfout(regs, 6, dev->sc_msg, MESG_OUT_PHASE);
-
- dev->sc_sync[id].state = SYNC_SENT;
-#ifdef DEBUG
- if (sync_debug)
- printf ("sent\n");
-#endif
- }
+ shift_nosync += 8;
- SBIC_WAIT (regs, SBIC_ASR_INT, 0);
- GET_SBIC_csr (regs, csr);
- QPRINTF(("[%02x]", csr));
#ifdef DEBUG
- if (sync_debug && dev->sc_sync[id].state == SYNC_SENT)
- printf("csr-result of last msgout: 0x%x\n", csr);
+ if ( inhibit_sync )
+ printf("%s: Inhibiting synchronous transfer %02x\n",
+ dev->sc_dev.dv_xname, inhibit_sync);
#endif
+ for (i = 0; i < 8; ++i) {
+ if ( inhibit_sync & (1 << i) )
+ sbic_inhibit_sync[i] = 1;
+ }
+ }
- if (csr != SBIC_CSR_SEL_TIMEO)
- dev->sc_flags |= SBICF_SELECTED;
- }
- if (csr == SBIC_CSR_SEL_TIMEO)
- dev->sc_xs->error = XS_SELTIMEOUT;
-
- QPRINTF(("\n"));
-
- return(csr == SBIC_CSR_SEL_TIMEO);
-}
-
-int
-sbicxfstart(regs, len, phase, wait)
- sbic_regmap_p regs;
- int len, wait;
- u_char phase;
-{
- u_char id;
-
- switch (phase) {
- case DATA_IN_PHASE:
- case MESG_IN_PHASE:
- GET_SBIC_selid (regs, id);
- id |= SBIC_SID_FROM_SCSI;
- SET_SBIC_selid (regs, id);
- SBIC_TC_PUT (regs, (unsigned)len);
- break;
- case DATA_OUT_PHASE:
- case MESG_OUT_PHASE:
- case CMD_PHASE:
- GET_SBIC_selid (regs, id);
- id &= ~SBIC_SID_FROM_SCSI;
- SET_SBIC_selid (regs, id);
- SBIC_TC_PUT (regs, (unsigned)len);
- break;
- default:
- SBIC_TC_PUT (regs, 0);
- }
- QPRINTF(("sbicxfstart %d, %d, %d\n", len, phase, wait));
-
- return(1);
+ sbicreset(dev);
}
-int
-sbicxfout(regs, len, bp, phase)
- sbic_regmap_p regs;
- int len;
- void *bp;
- int phase;
+void
+sbicreset(dev)
+ struct sbic_softc *dev;
{
- u_char orig_csr, csr, asr, *buf;
- int wait;
-
- buf = bp;
- wait = sbic_data_wait;
-
- QPRINTF(("sbicxfout {%d} %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x\n", len, buf[0], buf[1], buf[2],
- buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]));
-
- GET_SBIC_csr (regs, orig_csr);
-
- /*
- * sigh.. WD-PROTO strikes again.. sending the command in one go
- * causes the chip to lock up if talking to certain (misbehaving?)
- * targets. Anyway, this procedure should work for all targets, but
- * it's slightly slower due to the overhead
- */
- WAIT_CIP (regs);
- SET_SBIC_cmd (regs, SBIC_CMD_XFER_INFO);
- for (;len > 0; len--) {
- GET_SBIC_asr (regs, asr);
- while ((asr & SBIC_ASR_DBR) == 0) {
- if ((asr & SBIC_ASR_INT) || --wait < 0) {
-#ifdef DEBUG
- if (sbic_debug)
- printf("sbicxfout fail: l%d i%x w%d\n",
- len, asr, wait);
-#endif
- return (len);
- }
-/* DELAY(1);*/
- GET_SBIC_asr (regs, asr);
- }
-
- SET_SBIC_data (regs, *buf);
- buf++;
- }
- SBIC_TC_GET(regs, len);
- QPRINTF(("sbicxfout done %d bytes\n", len));
- /*
- * this leaves with one csr to be read
- */
- return(0);
+ sbic_regmap_p regs = dev->sc_sbicp;
+ u_int my_id,
+ s;
+ u_char csr;
+
+ s = splbio();
+
+ my_id = dev->sc_link.adapter_target & SBIC_ID_MASK;
+
+ if (dev->sc_clkfreq < 110)
+ my_id |= SBIC_ID_FS_8_10;
+ else if (dev->sc_clkfreq < 160)
+ my_id |= SBIC_ID_FS_12_15;
+ else if (dev->sc_clkfreq < 210)
+ my_id |= SBIC_ID_FS_16_20;
+
+ SET_SBIC_myid(regs, my_id);
+
+ /*
+ * Reset the chip
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_RESET);
+ DELAY(25);
+
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(regs, csr); /* clears interrupt also */
+
+ /*
+ * Set up various chip parameters
+ */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+ /*
+ * don't allow Selection (SBIC_RID_ES)
+ * until we can handle target mode!!
+ */
+ SET_SBIC_rselid(regs, SBIC_RID_ER);
+
+ /*
+ * Asynchronous for now
+ */
+ SET_SBIC_syn(regs, 0);
+
+ /*
+ * Anything else was zeroed by reset
+ */
+ splx(s);
+
+ dev->sc_flags &= ~SBICF_SELECTED;
}
-/* returns # bytes left to read */
-int
-sbicxfin(regs, len, bp)
- sbic_regmap_p regs;
- int len;
- void *bp;
+void
+sbicerror(dev, csr)
+ struct sbic_softc *dev;
+ u_char csr;
{
- int wait, read;
- u_char *obp, *buf;
- u_char orig_csr, csr, asr;
+ struct scsi_xfer *xs = dev->sc_xs;
- wait = sbic_data_wait;
- obp = bp;
- buf = bp;
+#ifdef DIAGNOSTIC
+ if ( xs == NULL )
+ panic("sbicerror: dev->sc_xs == NULL");
+#endif
- GET_SBIC_csr (regs, orig_csr);
+ if ( xs->flags & SCSI_SILENT )
+ return;
- QPRINTF(("sbicxfin %d, csr=%02x\n", len, orig_csr));
+ printf("%s: csr == 0x%02x\n", dev->sc_dev.dv_xname, csr);
+}
- WAIT_CIP (regs);
- SET_SBIC_cmd (regs, SBIC_CMD_XFER_INFO);
- for (;len > 0; len--) {
- GET_SBIC_asr (regs, asr);
- if((asr & SBIC_ASR_PE)) {
+/*
+ * select the bus, return when selected or error.
+ *
+ * Returns the current CSR following selection and optionally MSG out phase.
+ * i.e. the returned CSR *should* indicate CMD phase...
+ * If the return value is 0, some error happened.
+ */
+u_char
+sbicselectbus(dev)
+ struct sbic_softc *dev;
+{
+ sbic_regmap_p regs = dev->sc_sbicp;
+ u_char target = dev->target,
+ lun = dev->lun,
+ asr,
+ csr,
+ id;
+
+ /*
+ * if we're already selected, return (XXXX panic maybe?)
+ */
+ if ( dev->sc_flags & SBICF_SELECTED )
+ return(0);
+
+ QPRINTF(("sbicselectbus %d: ", target));
+
+ /*
+ * issue select
+ */
+ SET_SBIC_selid(regs, target);
+ SET_SBIC_timeo(regs, SBIC_TIMEOUT(250, dev->sc_clkfreq));
+
+ /*
+ * set sync or async
+ */
+ if ( dev->sc_sync[target].state == SYNC_DONE )
+ SET_SBIC_syn(regs, SBIC_SYN(dev->sc_sync[target].offset,
+ dev->sc_sync[target].period));
+ else
+ SET_SBIC_syn(regs, SBIC_SYN(0, sbic_min_period));
+
+ GET_SBIC_asr(regs, asr);
+
+ if ( asr & (SBIC_ASR_INT|SBIC_ASR_BSY) ) {
+ /*
+ * This means we got ourselves reselected upon
+ */
+ QPRINTF(("WD busy (reselect?)\n"));
+ return 0;
+ }
+
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN);
+
+ /*
+ * wait for select (merged from seperate function may need
+ * cleanup)
+ */
+ WAIT_CIP(regs);
+
+ do {
+
+ asr = SBIC_WAIT(regs, SBIC_ASR_INT | SBIC_ASR_LCI, 0);
+
+ if ( asr & SBIC_ASR_LCI ) {
+ QPRINTF(("late LCI: asr %02x\n", asr));
+ return 0;
+ }
+
+ /*
+ * Clear interrupt
+ */
+ GET_SBIC_csr (regs, csr);
+
+ QPRINTF(("%02x ", csr));
+
+ /*
+ * Reselected from under our feet?
+ */
+ if ( csr == SBIC_CSR_RSLT_NI || csr == SBIC_CSR_RSLT_IFY ) {
+ QPRINTF(("got reselected, asr %02x\n", asr));
+ /*
+ * We need to handle this now so we don't lock up later
+ */
+ sbicnextstate(dev, csr, asr);
+
+ return 0;
+ }
+
+ /*
+ * Whoops!
+ */
+ if ( csr == SBIC_CSR_SLT || csr == SBIC_CSR_SLT_ATN ) {
+ panic("sbicselectbus: target issued select!");
+ return 0;
+ }
+
+ } while (csr != (SBIC_CSR_MIS_2 | MESG_OUT_PHASE) &&
+ csr != (SBIC_CSR_MIS_2 | CMD_PHASE) &&
+ csr != SBIC_CSR_SEL_TIMEO);
+
+ /*
+ * Anyone at home?
+ */
+ if ( csr == SBIC_CSR_SEL_TIMEO ) {
+ dev->sc_xs->error = XS_SELTIMEOUT;
+ QPRINTF(("Selection Timeout\n"));
+ return 0;
+ }
+
+ QPRINTF(("Selection Complete\n"));
+
+ /*
+ * Assume we're now selected
+ */
+ GET_SBIC_selid(regs, id);
+ dev->target = id;
+ dev->lun = lun;
+ dev->sc_flags |= SBICF_SELECTED;
+
+ /*
+ * Enable (or not) reselection
+ * XXXSCW This is probably not necessary since we don't use use the
+ * Select-and-Xfer-with-ATN command to initialte a selection...
+ */
+ if ( !sbic_enable_reselect && dev->nexus_list.tqh_first == NULL)
+ SET_SBIC_rselid (regs, 0);
+ else
+ SET_SBIC_rselid (regs, SBIC_RID_ER);
+
+ /*
+ * We only really need to do anything when the target goes to MSG out
+ * If the device ignored ATN, it's probably old and brain-dead,
+ * but we'll try to support it anyhow.
+ * If it doesn't support message out, it definately doesn't
+ * support synchronous transfers, so no point in even asking...
+ */
+ if ( csr == (SBIC_CSR_MIS_2 | MESG_OUT_PHASE) ) {
+ /*
+ * Send identify message (SCSI-2 requires an identify msg)
+ */
+ if ( sbic_inhibit_sync[id] && dev->sc_sync[id].state == SYNC_START ) {
+ /*
+ * Handle drives that don't want to be asked
+ * whether to go sync at all.
+ */
+ dev->sc_sync[id].offset = 0;
+ dev->sc_sync[id].period = sbic_min_period;
+ dev->sc_sync[id].state = SYNC_DONE;
+ }
+
+ /*
+ * Do we need to negotiate Synchronous Xfers for this target?
+ */
+ if ( dev->sc_sync[id].state != SYNC_START ) {
+ /*
+ * Nope, we've already negotiated.
+ * Now see if we should allow the target to disconnect/reselect...
+ */
+ if ( dev->sc_xs->flags & SCSI_POLL || dev->sc_flags & SBICF_ICMD ||
+ !sbic_enable_reselect )
+ SEND_BYTE (regs, MSG_IDENTIFY | lun);
+ else
+ SEND_BYTE (regs, MSG_IDENTIFY_DR | lun);
+
+ } else {
+ /*
+ * try to initiate a sync transfer.
+ * So compose the sync message we're going
+ * to send to the target
+ */
#ifdef DEBUG
- printf("sbicxfin parity error: l%d i%x w%d\n",
- len, asr, wait);
-/* return ((unsigned long)buf - (unsigned long)bp); */
-#ifdef DDB
- Debugger();
-#endif
-#endif
- }
- while ((asr & SBIC_ASR_DBR) == 0) {
- if ((asr & SBIC_ASR_INT) || --wait < 0) {
+ if ( sync_debug )
+ printf("\nSending sync request to target %d ... ", id);
+#endif
+ /*
+ * setup scsi message sync message request
+ */
+ dev->sc_msg[0] = MSG_IDENTIFY | lun;
+ dev->sc_msg[1] = MSG_EXT_MESSAGE;
+ dev->sc_msg[2] = 3;
+ dev->sc_msg[3] = MSG_SYNC_REQ;
+ dev->sc_msg[4] = sbictoscsiperiod(dev, sbic_min_period);
+ dev->sc_msg[5] = sbic_max_offset;
+
+ sbicxfout(regs, 6, dev->sc_msg);
+
+ dev->sc_sync[id].state = SYNC_SENT;
#ifdef DEBUG
- if (sbic_debug) {
- QPRINTF(("sbicxfin fail:{%d} %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x\n", len, obp[0], obp[1], obp[2],
- obp[3], obp[4], obp[5], obp[6], obp[7], obp[8], obp[9]));
- printf("sbicxfin fail: l%d i%x w%d\n",
- len, asr, wait);
-}
+ if ( sync_debug )
+ printf ("sent\n");
#endif
- return len;
- }
+ }
- if( ! asr & SBIC_ASR_BSY ) {
- GET_SBIC_csr(regs, csr);
- QPRINTF(("[CSR%02xASR%02x]", csr, asr));
- }
+ /*
+ * There's one interrupt still to come: the change to CMD phase...
+ */
+ SBIC_WAIT(regs, SBIC_ASR_INT , 0);
+ GET_SBIC_csr(regs, csr);
+ }
-/* DELAY(1);*/
- GET_SBIC_asr (regs, asr);
- }
-
- GET_SBIC_data (regs, *buf);
-/* QPRINTF(("asr=%02x, csr=%02x, data=%02x\n", asr, csr, *buf));*/
- buf++;
- }
+ return csr;
+}
- QPRINTF(("sbicxfin {%d} %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x\n", len, obp[0], obp[1], obp[2],
- obp[3], obp[4], obp[5], obp[6], obp[7], obp[8], obp[9]));
+/*
+ * Information Transfer *to* a Scsi Target
+ */
+int
+sbicxfout(regs, len, bp)
+ sbic_regmap_p regs;
+ int len;
+ void *bp;
+{
+ int wait = sbic_data_wait;
+ u_char asr,
+ *buf = bp;
+
+ QPRINTF(("sbicxfout {%d} %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x\n", len, buf[0], buf[1], buf[2],
+ buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]));
+
+ /*
+ * sigh.. WD-PROTO strikes again.. sending the command in one go
+ * causes the chip to lock up if talking to certain (misbehaving?)
+ * targets. Anyway, this procedure should work for all targets, but
+ * it's slightly slower due to the overhead
+ */
+ WAIT_CIP (regs);
+
+ SBIC_TC_PUT (regs, 0);
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+ SBIC_TC_PUT (regs, (unsigned)len);
+ SET_SBIC_cmd (regs, SBIC_CMD_XFER_INFO);
+
+ /*
+ * Loop for each byte transferred
+ */
+ do {
+
+ GET_SBIC_asr (regs, asr);
+
+ if ( asr & SBIC_ASR_DBR ) {
+ if ( len ) {
+ SET_SBIC_data (regs, *buf);
+ buf++;
+ len--;
+ } else {
+ SET_SBIC_data (regs, 0);
+ }
+ wait = sbic_data_wait;
+ }
+
+ } while ( (asr & SBIC_ASR_INT) == 0 && wait-- > 0 );
+
+ SBIC_TC_GET(regs, len);
+ SBIC_TC_PUT(regs, 0);
+
+#ifdef DEBUG
+ QPRINTF(("sbicxfout done: %d bytes remaining (wait:%d)\n", len, wait));
+#endif
+
+ /*
+ * this leaves with one csr to be read
+ */
+ return(len);
+}
- /* this leaves with one csr to be read */
- return len;
+/*
+ * Information Transfer *from* a Scsi Target
+ * returns # bytes left to read
+ */
+int
+sbicxfin(regs, len, bp)
+ sbic_regmap_p regs;
+ int len;
+ void *bp;
+{
+ int wait = sbic_data_wait;
+ u_char *buf = bp;
+ u_char asr;
+#ifdef DEBUG
+ u_char *obp = bp;
+#endif
+
+ WAIT_CIP (regs);
+
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+ SBIC_TC_PUT (regs, (unsigned)len);
+ SET_SBIC_cmd (regs, SBIC_CMD_XFER_INFO);
+
+ /*
+ * Loop for each byte transferred
+ */
+ do {
+
+ GET_SBIC_asr (regs, asr);
+
+ if ( asr & SBIC_ASR_DBR ) {
+ if ( len ) {
+ GET_SBIC_data (regs, *buf);
+ buf++;
+ len--;
+ } else {
+ u_char foo;
+ GET_SBIC_data (regs, foo);
+ }
+ wait = sbic_data_wait;
+ }
+
+ } while ( (asr & SBIC_ASR_INT) == 0 && wait-- > 0 );
+
+ QPRINTF(("sbicxfin {%d} %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x\n", len, obp[0], obp[1], obp[2],
+ obp[3], obp[4], obp[5], obp[6], obp[7], obp[8], obp[9]));
+
+ SBIC_TC_PUT (regs, 0);
+
+ /*
+ * this leaves with one csr to be read
+ */
+ return len;
}
/*
@@ -1258,242 +1304,186 @@ sbicxfin(regs, len, bp)
* command must supply no data.
*/
int
-sbicicmd(dev, target, lun, cbuf, clen, buf, len)
- struct sbic_softc *dev;
- void *cbuf, *buf;
- int clen, len;
+sbicicmd(dev, cbuf, clen, buf, len)
+ struct sbic_softc *dev;
+ void *cbuf,
+ *buf;
+ int clen,
+ len;
{
- sbic_regmap_p regs;
- u_char phase, csr, asr;
- int wait, newtarget, cmd_sent, parity_err;
- struct sbic_acb *acb;
-
- int discon;
- int i;
-
-#define CSR_LOG_BUF_SIZE 0
-#if CSR_LOG_BUF_SIZE
- int bufptr;
- int csrbuf[CSR_LOG_BUF_SIZE];
- bufptr=0;
-#endif
-
- regs = dev->sc_sbicp;
- acb = dev->sc_nexus;
-
- /* Make sure pointers are OK */
- dev->sc_last = dev->sc_cur = &acb->sc_pa;
- dev->sc_tcnt = acb->sc_tcnt = 0;
- acb->sc_pa.dc_count = 0; /* No DMA */
- acb->sc_kv.dc_addr = buf;
- acb->sc_kv.dc_count = len;
-
-#ifdef DEBUG
- routine = 3;
- debug_sbic_regs = regs; /* store this to allow debug calls */
- if( data_pointer_debug > 1 )
- printf("sbicicmd(%d,%d):%d\n", target, lun,
- acb->sc_kv.dc_count);
-#endif
-
- /*
- * set the sbic into non-DMA mode
- */
- SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI /*| SBIC_CTL_HSP*/);
-
- dev->sc_stat[0] = 0xff;
- dev->sc_msg[0] = 0xff;
- i = 1; /* pre-load */
-
- /* We're stealing the SCSI bus */
- dev->sc_flags |= SBICF_ICMD;
-
- do {
- /*
- * select the SCSI bus (it's an error if bus isn't free)
- */
- if (!( dev->sc_flags & SBICF_SELECTED )
- && sbicselectbus(dev, regs, target, lun, dev->sc_scsiaddr)) {
- /*printf("sbicicmd trying to select busy bus!\n");*/
- dev->sc_flags &= ~SBICF_ICMD;
- return(-1);
- }
-
- /*
- * Wait for a phase change (or error) then let the device sequence
- * us through the various SCSI phases.
- */
-
- wait = sbic_cmd_wait;
-
- GET_SBIC_asr (regs, asr);
- GET_SBIC_csr (regs, csr);
- QPRINTF((">ASR:%02xCSR:%02x<", asr, csr));
-
-#if CSR_LOG_BUF_SIZE
- csrbuf[bufptr++] = csr;
-#endif
-
-
- switch (csr) {
- case SBIC_CSR_S_XFERRED:
- case SBIC_CSR_DISC:
- case SBIC_CSR_DISC_1:
- dev->sc_flags &= ~SBICF_SELECTED;
- GET_SBIC_cmd_phase (regs, phase);
- if (phase == 0x60) {
- GET_SBIC_tlun (regs, dev->sc_stat[0]);
- i = 0; /* done */
-/* break; /* Bypass all the state gobldygook */
- } else {
+ sbic_regmap_p regs = dev->sc_sbicp;
+ struct sbic_acb *acb = dev->sc_nexus;
+ u_char csr,
+ asr;
+ int still_busy = 1;
+
+ /*
+ * Make sure pointers are OK
+ */
+ dev->sc_last = dev->sc_cur = &acb->sc_pa;
+ dev->sc_tcnt = acb->sc_tcnt = 0;
+
+ acb->sc_dmacmd = 0;
+ acb->sc_pa.dc_count = 0; /* No DMA */
+ acb->sc_kv.dc_addr = buf;
+ acb->sc_kv.dc_count = len;
+
+#ifdef DEBUG
+ if ( data_pointer_debug > 1 )
+ printf("sbicicmd(%d,%d):%d\n", dev->target, dev->lun, acb->sc_kv.dc_count);
+#endif
+
+ /*
+ * set the sbic into non-DMA mode
+ */
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+ dev->sc_stat[0] = 0xff;
+ dev->sc_msg[0] = 0xff;
+
+ /*
+ * We're stealing the SCSI bus
+ */
+ dev->sc_flags |= SBICF_ICMD;
+
+ do {
+ GET_SBIC_asr (regs, asr);
+
+ /*
+ * select the SCSI bus (it's an error if bus isn't free)
+ */
+ if ( (dev->sc_flags & SBICF_SELECTED) == 0 ) {
+ if ( (csr = sbicselectbus(dev)) == 0 ) {
+ dev->sc_flags &= ~SBICF_ICMD;
+ return(-1);
+ }
+ } else
+ GET_SBIC_csr(regs, csr);
+
+ QPRINTF((">ASR:0x%02x CSR:0x%02x <", asr, csr));
+
+ switch ( csr ) {
+
+ case SBIC_CSR_S_XFERRED:
+ case SBIC_CSR_DISC:
+ case SBIC_CSR_DISC_1:
+ {
+ u_char phase;
+
+ dev->sc_flags &= ~SBICF_SELECTED;
+ GET_SBIC_cmd_phase (regs, phase);
+
+ if ( phase == 0x60 ) {
+ GET_SBIC_tlun (regs, dev->sc_stat[0]);
+ still_busy = 0; /* done */
+ } else {
#ifdef DEBUG
- if(reselect_debug>1)
- printf("sbicicmd: handling disconnect\n");
-#endif
- i = SBIC_STATE_DISCONNECT;
- }
- break;
-
- case SBIC_CSR_XFERRED|CMD_PHASE:
- case SBIC_CSR_MIS|CMD_PHASE:
- case SBIC_CSR_MIS_1|CMD_PHASE:
- case SBIC_CSR_MIS_2|CMD_PHASE:
- if (sbicxfstart(regs, clen, CMD_PHASE, sbic_cmd_wait))
- if (sbicxfout(regs, clen,
- cbuf, CMD_PHASE))
- i = sbicabort(dev, regs,"icmd sending cmd");
-#if 0
- GET_SBIC_csr(regs, csr); /* Lets us reload tcount */
- WAIT_CIP(regs);
- GET_SBIC_asr(regs, asr);
- if( asr & (SBIC_ASR_BSY|SBIC_ASR_LCI|SBIC_ASR_CIP) )
- printf("next: cmd sent asr %02x, csr %02x\n",
- asr, csr);
-#endif
- break;
-
-#if 0
- case SBIC_CSR_XFERRED|DATA_OUT_PHASE:
- case SBIC_CSR_XFERRED|DATA_IN_PHASE:
- case SBIC_CSR_MIS|DATA_OUT_PHASE:
- case SBIC_CSR_MIS|DATA_IN_PHASE:
- case SBIC_CSR_MIS_1|DATA_OUT_PHASE:
- case SBIC_CSR_MIS_1|DATA_IN_PHASE:
- case SBIC_CSR_MIS_2|DATA_OUT_PHASE:
- case SBIC_CSR_MIS_2|DATA_IN_PHASE:
- if (acb->sc_kv.dc_count <= 0)
- i = sbicabort(dev, regs, "icmd out of data");
- else {
- wait = sbic_data_wait;
- if (sbicxfstart(regs,
- acb->sc_kv.dc_count,
- SBIC_PHASE(csr), wait))
- if (csr & 0x01)
- /* data in? */
- i=sbicxfin(regs,
- acb->sc_kv.dc_count,
- acb->sc_kv.dc_addr);
- else
- i=sbicxfout(regs,
- acb->sc_kv.dc_count,
- acb->sc_kv.dc_addr,
- SBIC_PHASE(csr));
- acb->sc_kv.dc_addr +=
- (acb->sc_kv.dc_count - i);
- acb->sc_kv.dc_count = i;
- i = 1;
- }
- break;
-
-#endif
- case SBIC_CSR_XFERRED|STATUS_PHASE:
- case SBIC_CSR_MIS|STATUS_PHASE:
- case SBIC_CSR_MIS_1|STATUS_PHASE:
- case SBIC_CSR_MIS_2|STATUS_PHASE:
- /*
- * the sbic does the status/cmd-complete reading ok,
- * so do this with its hi-level commands.
- */
+ if ( reselect_debug > 1 )
+ printf("sbicicmd: handling disconnect\n");
+#endif
+ still_busy = SBIC_STATE_DISCONNECT;
+ }
+ }
+ break;
+
+ case SBIC_CSR_XFERRED | CMD_PHASE:
+ case SBIC_CSR_MIS | CMD_PHASE:
+ case SBIC_CSR_MIS_1 | CMD_PHASE:
+ case SBIC_CSR_MIS_2 | CMD_PHASE:
+ {
+ if ( sbicxfout(regs, clen, cbuf) )
+ still_busy = sbicabort(dev, "icmd sending cmd");
+ }
+ break;
+
+ case SBIC_CSR_XFERRED | STATUS_PHASE:
+ case SBIC_CSR_MIS | STATUS_PHASE:
+ case SBIC_CSR_MIS_1 | STATUS_PHASE:
+ case SBIC_CSR_MIS_2 | STATUS_PHASE:
+ {
+ /*
+ * The sbic does the status/cmd-complete reading ok,
+ * so do this with its hi-level commands.
+ */
#ifdef DEBUG
- if(sbic_debug)
- printf("SBICICMD status phase\n");
-#endif
- SBIC_TC_PUT(regs, 0);
- SET_SBIC_cmd_phase(regs, 0x46);
- SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN_XFER);
- break;
-
-#if THIS_IS_A_RESERVED_STATE
- case BUS_FREE_PHASE: /* This is not legal */
- if( dev->sc_stat[0] != 0xff )
- goto out;
- break;
-#endif
-
- default:
- i = sbicnextstate(dev, csr, asr);
- }
-
- /*
- * make sure the last command was taken,
- * ie. we're not hunting after an ignored command..
- */
- GET_SBIC_asr(regs, asr);
-
- /* tapes may take a loooong time.. */
- while (asr & SBIC_ASR_BSY){
- if(asr & SBIC_ASR_DBR) {
- printf("sbicicmd: Waiting while sbic is jammed, CSR:%02x,ASR:%02x\n",
- csr,asr);
+ if ( sbic_debug )
+ printf("SBICICMD status phase (bsy=%d)\n", still_busy);
+#endif
+ SET_SBIC_cmd_phase(regs, 0x46);
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN_XFER);
+ }
+ break;
+
+ default:
+ {
+ still_busy = sbicnextstate(dev, csr, asr);
+ }
+ break;
+ }
+
+ /*
+ * make sure the last command was taken,
+ * ie. we're not hunting after an ignored command..
+ */
+ GET_SBIC_asr(regs, asr);
+
+ /*
+ * tapes may take a loooong time..
+ */
+ while (asr & SBIC_ASR_BSY ) {
+
+ if ( asr & SBIC_ASR_DBR ) {
+ int i;
+
+ printf("sbicicmd: Waiting while sbic is jammed, CSR:%02x,ASR:%02x\n", csr,asr);
#ifdef DDB
- Debugger();
-#endif
- /* SBIC is jammed */
- /* DUNNO which direction */
- /* Try old direction */
- GET_SBIC_data(regs,i);
- GET_SBIC_asr(regs, asr);
- if( asr & SBIC_ASR_DBR) /* Wants us to write */
- SET_SBIC_data(regs,i);
- }
- GET_SBIC_asr(regs, asr);
- }
-
- /*
- * wait for last command to complete
- */
- if (asr & SBIC_ASR_LCI) {
- printf("sbicicmd: last command ignored\n");
- }
- else if( i == 1 ) /* Bsy */
- SBIC_WAIT (regs, SBIC_ASR_INT, wait);
-
- /*
- * do it again
- */
- } while ( i > 0 && dev->sc_stat[0] == 0xff);
-
- /* Sometimes we need to do an extra read of the CSR */
- GET_SBIC_csr(regs, csr);
-
-#if CSR_LOG_BUF_SIZE
- if(reselect_debug>1)
- for(i=0; i<bufptr; i++)
- printf("CSR:%02x", csrbuf[i]);
-#endif
+ Debugger();
+#endif
+ /*
+ * SBIC is jammed
+ * DUNNO which direction
+ * Try old direction
+ */
+ GET_SBIC_data(regs, i);
+ GET_SBIC_asr(regs, asr);
+
+ if ( asr & SBIC_ASR_DBR ) /* Wants us to write */
+ SET_SBIC_data(regs, i);
+ }
+
+ GET_SBIC_asr(regs, asr);
+ }
+
+ /*
+ * wait for last command to complete
+ */
+ if ( asr & SBIC_ASR_LCI ) {
+ printf("sbicicmd: last command ignored\n");
+ }
+ else
+ if ( still_busy == 1 ) /* Bsy */
+ SBIC_WAIT (regs, SBIC_ASR_INT, sbic_cmd_wait);
+
+ /*
+ * do it again
+ */
+ } while ( still_busy > 0 && dev->sc_stat[0] == 0xff );
+
+ /*
+ * Sometimes we need to do an extra read of the CSR
+ */
+ GET_SBIC_csr(regs, csr);
#ifdef DEBUG
- if(data_pointer_debug > 1)
- printf("sbicicmd done(%d,%d):%d =%d=\n",
- dev->target, lun,
- acb->sc_kv.dc_count,
- dev->sc_stat[0]);
+ if ( data_pointer_debug > 1 )
+ printf("sbicicmd done(%d,%d):%d =%d=\n", dev->target, dev->lun,
+ acb->sc_kv.dc_count,
+ dev->sc_stat[0]);
#endif
- QPRINTF(("=STS:%02x=", dev->sc_stat[0]));
- dev->sc_flags &= ~SBICF_ICMD;
+ dev->sc_flags &= ~SBICF_ICMD;
- return(dev->sc_stat[0]);
+ return(dev->sc_stat[0]);
}
/*
@@ -1503,1059 +1493,1176 @@ sbicicmd(dev, target, lun, cbuf, clen, buf, len)
* skip (and don't allow) the select, cmd out and data in/out phases.
*/
void
-sbicxfdone(dev, regs, target)
- struct sbic_softc *dev;
- sbic_regmap_p regs;
- int target;
+sbicxfdone(dev)
+ struct sbic_softc *dev;
{
- u_char phase, csr;
- int s;
-
- QPRINTF(("{"));
- s = splbio();
-
- /*
- * have the sbic complete on its own
- */
- SBIC_TC_PUT(regs, 0);
- SET_SBIC_cmd_phase(regs, 0x46);
- SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN_XFER);
-
- do {
- SBIC_WAIT (regs, SBIC_ASR_INT, 0);
- GET_SBIC_csr (regs, csr);
- QPRINTF(("%02x:", csr));
- } while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
- && (csr != SBIC_CSR_S_XFERRED));
-
- dev->sc_flags &= ~SBICF_SELECTED;
-
- GET_SBIC_cmd_phase (regs, phase);
- QPRINTF(("}%02x", phase));
- if (phase == 0x60)
- GET_SBIC_tlun(regs, dev->sc_stat[0]);
- else
- sbicerror(dev, regs, csr);
-
- QPRINTF(("=STS:%02x=\n", dev->sc_stat[0]));
- splx(s);
-}
+ sbic_regmap_p regs = dev->sc_sbicp;
+ u_char phase,
+ csr;
+ int s;
+
+ QPRINTF(("{"));
+ s = splbio();
+
+ /*
+ * have the sbic complete on its own
+ */
+ SBIC_TC_PUT(regs, 0);
+ SET_SBIC_cmd_phase(regs, 0x46);
+ SET_SBIC_cmd(regs, SBIC_CMD_SEL_ATN_XFER);
+
+ do {
- /*
- * No DMA chains
- */
+ SBIC_WAIT (regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr (regs, csr);
+ QPRINTF(("%02x:", csr));
+ } while ( (csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1) &&
+ (csr != SBIC_CSR_S_XFERRED));
+
+ dev->sc_flags &= ~SBICF_SELECTED;
+
+ GET_SBIC_cmd_phase (regs, phase);
+ QPRINTF(("}%02x", phase));
+
+ if ( phase == 0x60 )
+ GET_SBIC_tlun(regs, dev->sc_stat[0]);
+ else
+ sbicerror(dev, csr);
+
+ QPRINTF(("=STS:%02x=\n", dev->sc_stat[0]));
+
+ splx(s);
+}
+
+/*
+ * No DMA chains
+ */
int
sbicgo(dev, xs)
- struct sbic_softc *dev;
- struct scsi_xfer *xs;
+ struct sbic_softc *dev;
+ struct scsi_xfer *xs;
{
- int i, dmaflags, count, wait, usedma;
- u_char csr, asr, cmd, *addr;
- sbic_regmap_p regs;
- struct sbic_acb *acb;
+ struct sbic_acb *acb = dev->sc_nexus;
+ sbic_regmap_p regs = dev->sc_sbicp;
+ int i,
+ dmaflags,
+ count,
+ usedma;
+ u_char csr,
+ asr,
+ *addr;
- dev->target = xs->sc_link->target;
- dev->lun = xs->sc_link->lun;
- acb = dev->sc_nexus;
- regs = dev->sc_sbicp;
+ dev->target = xs->sc_link->target;
+ dev->lun = xs->sc_link->lun;
+
+ usedma = sbicdmaok(dev, xs);
- usedma = sbicdmaok(dev, xs);
#ifdef DEBUG
- routine = 1;
- debug_sbic_regs = regs; /* store this to allow debug calls */
- if( data_pointer_debug > 1 )
- printf("sbicgo(%d,%d)\n", dev->target, dev->lun);
+ if ( data_pointer_debug > 1 )
+ printf("sbicgo(%d,%d): usedma=%d\n", dev->target, dev->lun, usedma);
#endif
- /*
- * set the sbic into DMA mode
- */
- if( usedma )
- SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI |
- SBIC_MACHINE_DMA_MODE);
- else
- SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
-
-
- /*
- * select the SCSI bus (it's an error if bus isn't free)
- */
- if (sbicselectbus(dev, regs, dev->target, dev->lun,
- dev->sc_scsiaddr)) {
-/* printf("sbicgo: Trying to select busy bus!\n"); */
- return(0); /* Not done: needs to be rescheduled */
- }
- dev->sc_stat[0] = 0xff;
-
- /*
- * Calculate DMA chains now
- */
-
- dmaflags = 0;
- if (acb->flags & ACB_DATAIN)
- dmaflags |= DMAGO_READ;
-
-
- /*
- * Deal w/bounce buffers.
- */
-
- addr = acb->sc_kv.dc_addr;
- count = acb->sc_kv.dc_count;
- if (count && (char *)kvtop(addr) != acb->sc_pa.dc_addr) { /* XXXX check */
- printf("sbic: DMA buffer mapping changed %x->%x\n",
- acb->sc_pa.dc_addr, kvtop(addr));
+ /*
+ * select the SCSI bus (it's an error if bus isn't free)
+ */
+ if ( (csr = sbicselectbus(dev)) == 0 )
+ return(0); /* Not done: needs to be rescheduled */
+
+ dev->sc_stat[0] = 0xff;
+
+ /*
+ * Calculate DMA chains now
+ */
+ if ( acb->flags & ACB_DATAIN )
+ dmaflags = DMAGO_READ;
+ else
+ dmaflags = 0;
+
+ addr = acb->sc_kv.dc_addr;
+ count = acb->sc_kv.dc_count;
+
+ if ( count && ((char *)kvtop(addr) != acb->sc_pa.dc_addr) ) {
+ printf("sbic: DMA buffer mapping changed %x->%x\n",
+ acb->sc_pa.dc_addr, kvtop(addr));
#ifdef DDB
- Debugger();
+ Debugger();
#endif
- }
+ }
#ifdef DEBUG
- ++sbicdma_ops; /* count total DMA operations */
-#endif
- if (count && usedma && dev->sc_flags & SBICF_BADDMA &&
- sbiccheckdmap(addr, count, dev->sc_dmamask)) {
- /*
- * need to bounce the dma.
- */
- if (dmaflags & DMAGO_READ) {
- acb->flags |= ACB_BBUF;
- acb->sc_dmausrbuf = addr;
- acb->sc_dmausrlen = count;
- acb->sc_usrbufpa = (u_char *)kvtop(addr);
- if(!dev->sc_tinfo[dev->target].bounce) {
- printf("sbicgo: HELP! no bounce allocated for %d\n",
- dev->target);
- printf("xfer: (%x->%x,%x)\n", acb->sc_dmausrbuf,
- acb->sc_usrbufpa, acb->sc_dmausrlen);
-#if 0
- dev->sc_tinfo[xs->sc_link->target].bounce
- = (char *)alloc_z2mem(MAXPHYS);
- if (isztwomem(dev->sc_tinfo[xs->sc_link->target].bounce))
- printf("alloc ZII target %d bounce pa 0x%x\n",
- xs->sc_link->target,
- kvtop(dev->sc_tinfo[xs->sc_link->target].bounce));
- else if (dev->sc_tinfo[xs->sc_link->target].bounce)
- printf("alloc CHIP target %d bounce pa 0x%x\n",
- xs->sc_link->target,
- PREP_DMA_MEM(dev->sc_tinfo[xs->sc_link->target].bounce));
+ ++sbicdma_ops; /* count total DMA operations */
#endif
- printf("Allocating %d bounce at %x\n",
- dev->target,
- kvtop(dev->sc_tinfo[dev->target].bounce));
- }
- } else { /* write: copy to dma buffer */
+ /*
+ * Allocate the DMA chain
+ * Mark end of segment...
+ */
+ acb->sc_tcnt = dev->sc_tcnt = 0;
+ acb->sc_pa.dc_count = 0;
+
+ sbic_load_ptrs(dev);
+
+ /*
+ * Enable interrupts but don't do any DMA
+ * enintr() also enables interrupts for the sbic
+ */
+ dev->sc_enintr(dev);
+
+ if ( usedma ) {
+ dev->sc_tcnt = dev->sc_dmago(dev, acb->sc_pa.dc_addr,
+ acb->sc_pa.dc_count, dmaflags);
#ifdef DEBUG
- if(data_pointer_debug)
- printf("sbicgo: copying %x bytes to target %d bounce %x\n",
- count, dev->target,
- kvtop(dev->sc_tinfo[dev->target].bounce));
+ dev->sc_dmatimo = dev->sc_tcnt ? 1 : 0;
#endif
- bcopy (addr, dev->sc_tinfo[dev->target].bounce, count);
- }
- addr = dev->sc_tinfo[dev->target].bounce;/* and use dma buffer */
- acb->sc_kv.dc_addr = addr;
+ } else
+ dev->sc_dmacmd = 0; /* Don't use DMA */
+
+ acb->sc_dmacmd = dev->sc_dmacmd;
+
#ifdef DEBUG
- ++sbicdma_bounces; /* count number of bounced */
+ if ( data_pointer_debug > 1 ) {
+ printf("sbicgo dmago:%d(%x:%x) dmacmd=0x%02x\n", dev->target,
+ dev->sc_cur->dc_addr,
+ dev->sc_tcnt,
+ dev->sc_dmacmd);
+ }
#endif
- }
- /*
- * Allocate the DMA chain
- */
+ /*
+ * Lets cycle a while then let the interrupt handler take over.
+ */
+ GET_SBIC_asr(regs, asr);
- /* Set start KVM addresses */
-#if 0
- acb->sc_kv.dc_addr = addr;
- acb->sc_kv.dc_count = count;
-#endif
+ do {
- /* Mark end of segment */
- acb->sc_tcnt = dev->sc_tcnt = 0;
- acb->sc_pa.dc_count = 0;
-
- sbic_load_ptrs(dev, regs, dev->target, dev->lun);
- /* Enable interrupts but don't do any DMA */
- dev->sc_tcnt = dev->sc_dmago(dev, acb->sc_pa.dc_addr,
- acb->sc_pa.dc_count,
- dmaflags);
- dev->sc_flags |= SBICF_INDMA;
- if( !usedma )
- dev->sc_dmacmd = 0; /* Don't use DMA */
-/* SBIC_TC_PUT(regs, dev->sc_tcnt); /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
- sbic_save_ptrs(dev, regs, dev->target, dev->lun);
-
- /*
- * push the data cache ( I think this won't work (EH))
- */
-#if defined(M68040)
- if (mmutype == MMU_68040 && usedma && count) {
- dma_cachectl(addr, count);
- if (((u_int)addr & 0xF) || (((u_int)addr + count) & 0xF))
- dev->sc_flags |= SBICF_DCFLUSH;
- }
-#endif
+ QPRINTF(("go "));
- /*
- * dmago() also enables interrupts for the sbic
- */
-#ifdef DEBUG
- if( data_pointer_debug > 1 )
- printf("sbicgo dmago:%d(%x:%x)\n",
- dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
- if( sbic_timeout && !timeout_active ) {
- timeout((void *)sbictimeout, (void*)dev, sbic_timeout * hz);
- timeout_active = 1;
- }
- debug_asr = asr;
- debug_csr = csr;
+ /*
+ * Handle the new phase
+ */
+ i = sbicnextstate(dev, csr, asr);
+#if 0
+ WAIT_CIP(regs);
#endif
+ if ( i == SBIC_STATE_RUNNING ) {
+ GET_SBIC_asr(regs, asr);
- /*
- * Lets cycle a while then let the interrupt handler take over
- */
+ if ( asr & SBIC_ASR_LCI )
+ printf("sbicgo: LCI asr:%02x csr:%02x\n", asr, csr);
- GET_SBIC_asr(regs, asr);
- do {
- GET_SBIC_csr(regs, csr);
-#ifdef DEBUG
- debug_csr = csr;
- routine = 1;
-#endif
- QPRINTF(("go[0x%x]", csr));
+ if ( asr & SBIC_ASR_INT )
+ GET_SBIC_csr(regs, csr);
+ }
- i = sbicnextstate(dev, csr, asr);
+ } while ( i == SBIC_STATE_RUNNING && asr & (SBIC_ASR_INT|SBIC_ASR_LCI) );
- WAIT_CIP(regs);
- GET_SBIC_asr(regs, asr);
-#ifdef DEBUG
- debug_asr = asr;
+ if ( i == SBIC_STATE_DONE ) {
+ if ( dev->sc_stat[0] == 0xff )
+#if 0
+ printf("sbicgo: done & stat = 0xff\n");
+#else
+ ;
#endif
- if(asr & SBIC_ASR_LCI) printf("sbicgo: LCI asr:%02x csr:%02x\n",
- asr,csr);
- } while( i == SBIC_STATE_RUNNING
- && asr & (SBIC_ASR_INT|SBIC_ASR_LCI) );
-
- if (i == SBIC_STATE_DONE && dev->sc_stat[0] != 0xff) {
- /* Did we really finish that fast? */
- return 1;
- }
- return 0;
+ else
+ return 1; /* Did we really finish that fast? */
+ }
+
+ return 0;
}
int
sbicintr(dev)
- struct sbic_softc *dev;
+ struct sbic_softc *dev;
{
- sbic_regmap_p regs;
- struct dma_chain *df, *dl;
- u_char asr, csr, *tmpaddr;
- struct sbic_acb *acb;
- int i, newtarget, newlun;
- unsigned tcnt;
-
- regs = dev->sc_sbicp;
-
- /*
- * pending interrupt?
- */
- GET_SBIC_asr (regs, asr);
- if ((asr & SBIC_ASR_INT) == 0)
- return(0);
-
- do {
- GET_SBIC_csr(regs, csr);
-#ifdef DEBUG
- debug_csr = csr;
- routine = 2;
-#endif
- QPRINTF(("intr[0x%x]", csr));
+ sbic_regmap_p regs = dev->sc_sbicp;
+ u_char asr,
+ csr;
+ int i;
- i = sbicnextstate(dev, csr, asr);
+ /*
+ * pending interrupt?
+ */
+ GET_SBIC_asr (regs, asr);
+ if ( (asr & SBIC_ASR_INT) == 0 )
+ return(0);
- WAIT_CIP(regs);
- GET_SBIC_asr(regs, asr);
-#ifdef DEBUG
- debug_asr = asr;
-#endif
+ do {
+
+ if ( asr & SBIC_ASR_INT )
+ GET_SBIC_csr(regs, csr);
+
+ QPRINTF(("intr[0x%x]", csr));
+
+ i = sbicnextstate(dev, csr, asr);
#if 0
- if(asr & SBIC_ASR_LCI) printf("sbicintr: LCI asr:%02x csr:%02x\n",
- asr,csr);
+ WAIT_CIP(regs);
#endif
- } while(i == SBIC_STATE_RUNNING &&
- asr & (SBIC_ASR_INT|SBIC_ASR_LCI));
- return(1);
+ GET_SBIC_asr(regs, asr);
+
+ } while ( i == SBIC_STATE_RUNNING && asr & (SBIC_ASR_INT|SBIC_ASR_LCI) );
+
+ QPRINTF(("intr done. state=%d, asr=0x%02x\n", i, asr));
+
+ return(1);
}
/*
- * Run commands and wait for disconnect
+ * Run commands and wait for disconnect.
+ * This is only ever called when a command is in progress, when we
+ * want to busy wait for it to finish.
*/
int
sbicpoll(dev)
- struct sbic_softc *dev;
+ struct sbic_softc *dev;
{
- sbic_regmap_p regs;
- u_char asr, csr;
- struct sbic_pending* pendp;
- int i;
- unsigned tcnt;
+ sbic_regmap_p regs = dev->sc_sbicp;
+ u_char asr,
+ csr;
+ int i;
- regs = dev->sc_sbicp;
+ /*
+ * Wait for the next interrupt
+ */
+ SBIC_WAIT(regs, SBIC_ASR_INT, sbic_cmd_wait);
- do {
- GET_SBIC_asr (regs, asr);
-#ifdef DEBUG
- debug_asr = asr;
-#endif
- GET_SBIC_csr(regs, csr);
-#ifdef DEBUG
- debug_csr = csr;
- routine = 2;
-#endif
- QPRINTF(("poll[0x%x]", csr));
+ do {
+ GET_SBIC_asr (regs, asr);
+
+ if ( asr & SBIC_ASR_INT )
+ GET_SBIC_csr(regs, csr);
+
+ QPRINTF(("poll[0x%x]", csr));
- i = sbicnextstate(dev, csr, asr);
+ /*
+ * Handle it
+ */
+ i = sbicnextstate(dev, csr, asr);
- WAIT_CIP(regs);
- GET_SBIC_asr(regs, asr);
- /* tapes may take a loooong time.. */
- while (asr & SBIC_ASR_BSY){
- if(asr & SBIC_ASR_DBR) {
- printf("sbipoll: Waiting while sbic is jammed, CSR:%02x,ASR:%02x\n",
- csr,asr);
+ WAIT_CIP(regs);
+ GET_SBIC_asr(regs, asr);
+
+ /*
+ * tapes may take a loooong time..
+ */
+ while ( asr & SBIC_ASR_BSY ) {
+
+ if ( asr & SBIC_ASR_DBR ) {
+ printf("sbipoll: Waiting while sbic is jammed, CSR:%02x,ASR:%02x\n", csr,asr);
#ifdef DDB
- Debugger();
+ Debugger();
#endif
- /* SBIC is jammed */
- /* DUNNO which direction */
- /* Try old direction */
- GET_SBIC_data(regs,i);
- GET_SBIC_asr(regs, asr);
- if( asr & SBIC_ASR_DBR) /* Wants us to write */
- SET_SBIC_data(regs,i);
- }
- GET_SBIC_asr(regs, asr);
- }
-
- if(asr & SBIC_ASR_LCI) printf("sbicpoll: LCI asr:%02x csr:%02x\n",
- asr,csr);
- else if( i == 1 ) /* BSY */
- SBIC_WAIT(regs, SBIC_ASR_INT, sbic_cmd_wait);
- } while(i == SBIC_STATE_RUNNING);
- return(1);
+ /*
+ * SBIC is jammed
+ * DUNNO which direction
+ * Try old direction
+ */
+ GET_SBIC_data(regs, i);
+ GET_SBIC_asr(regs, asr);
+
+ if ( asr & SBIC_ASR_DBR ) /* Wants us to write */
+ SET_SBIC_data(regs, i);
+ }
+
+ GET_SBIC_asr(regs, asr);
+ }
+
+ if ( asr & SBIC_ASR_LCI )
+ printf("sbicpoll: LCI asr:%02x csr:%02x\n", asr,csr);
+ else
+ if ( i == 1 ) /* BSY */
+ SBIC_WAIT(regs, SBIC_ASR_INT, sbic_cmd_wait);
+
+ } while ( i == SBIC_STATE_RUNNING );
+
+ return(1);
}
/*
* Handle a single msgin
*/
-
int
sbicmsgin(dev)
- struct sbic_softc *dev;
+ struct sbic_softc *dev;
{
- sbic_regmap_p regs;
- int recvlen;
- u_char asr, csr, *tmpaddr;
+ sbic_regmap_p regs = dev->sc_sbicp;
+ int recvlen = 1;
+ u_char asr,
+ csr,
+ *tmpaddr,
+ *msgaddr;
+
+ tmpaddr = msgaddr = dev->sc_msg;
- regs = dev->sc_sbicp;
+ tmpaddr[0] = 0xff;
+ tmpaddr[1] = 0xff;
- dev->sc_msg[0] = 0xff;
- dev->sc_msg[1] = 0xff;
+ GET_SBIC_asr(regs, asr);
- GET_SBIC_asr(regs, asr);
#ifdef DEBUG
- if(reselect_debug>1)
- printf("sbicmsgin asr=%02x\n", asr);
+ if ( reselect_debug > 1 )
+ printf("sbicmsgin asr=%02x\n", asr);
#endif
- sbic_save_ptrs(dev, regs, dev->target, dev->lun);
-
- GET_SBIC_selid (regs, csr);
- SET_SBIC_selid (regs, csr | SBIC_SID_FROM_SCSI);
-
- SBIC_TC_PUT(regs, 0);
- tmpaddr = dev->sc_msg;
- recvlen = 1;
- do {
- while( recvlen-- ) {
- GET_SBIC_asr(regs, asr);
- GET_SBIC_csr(regs, csr);
- QPRINTF(("sbicmsgin ready to go (csr,asr)=(%02x,%02x)\n",
- csr, asr));
-
- RECV_BYTE(regs, *tmpaddr);
-#if 1
- /*
- * get the command completion interrupt, or we
- * can't send a new command (LCI)
- */
- SBIC_WAIT(regs, SBIC_ASR_INT, 0);
- GET_SBIC_csr(regs, csr);
-#else
- WAIT_CIP(regs);
- do {
- GET_SBIC_asr(regs, asr);
- csr = 0xff;
- GET_SBIC_csr(regs, csr);
- if( csr == 0xff )
- printf("sbicmsgin waiting: csr %02x asr %02x\n", csr, asr);
- } while( csr == 0xff );
-#endif
+ GET_SBIC_selid (regs, csr);
+ SET_SBIC_selid (regs, csr | SBIC_SID_FROM_SCSI);
+
+ SBIC_TC_PUT(regs, 0);
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+ do {
+ while( recvlen-- ) {
+
+ /*
+ * Fetch the next byte of the message
+ */
+ RECV_BYTE(regs, *tmpaddr);
+
+ /*
+ * get the command completion interrupt, or we
+ * can't send a new command (LCI)
+ */
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(regs, csr);
+
#ifdef DEBUG
- if(reselect_debug>1)
- printf("sbicmsgin: got %02x csr %02x asr %02x\n",
- *tmpaddr, csr, asr);
-#endif
-#if do_parity_check
- if( asr & SBIC_ASR_PE ) {
- printf ("Parity error");
- /* This code simply does not work. */
- WAIT_CIP(regs);
- SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
- WAIT_CIP(regs);
- GET_SBIC_asr(regs, asr);
- WAIT_CIP(regs);
- SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
- WAIT_CIP(regs);
- if( !(asr & SBIC_ASR_LCI) )
- /* Target wants to send garbled msg*/
- continue;
- printf("--fixing\n");
- /* loop until a msgout phase occurs on target */
- while(csr & 0x07 != MESG_OUT_PHASE) {
- while( asr & SBIC_ASR_BSY &&
- !(asr & SBIC_ASR_DBR|SBIC_ASR_INT) )
- GET_SBIC_asr(regs, asr);
- if( asr & SBIC_ASR_DBR )
- panic("msgin: jammed again!\n");
- GET_SBIC_csr(regs, csr);
- if( csr & 0x07 != MESG_OUT_PHASE ) {
- sbicnextstate(dev, csr, asr);
- sbic_save_ptrs(dev, regs,
- dev->target,
- dev->lun);
- }
- }
- /* Should be msg out by now */
- SEND_BYTE(regs, MSG_PARITY_ERROR);
- }
- else
+ if ( reselect_debug > 1 )
+ printf("sbicmsgin: got %02x csr %02x\n", *tmpaddr, csr);
#endif
- tmpaddr++;
-
- if(recvlen) {
- /* Clear ACK */
- WAIT_CIP(regs);
- GET_SBIC_asr(regs, asr);
- GET_SBIC_csr(regs, csr);
- QPRINTF(("sbicmsgin pre byte CLR_ACK (csr,asr)=(%02x,%02x)\n",
- csr, asr));
- SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
- SBIC_WAIT(regs, SBIC_ASR_INT, 0);
- }
-
- };
-
- if(dev->sc_msg[0] == 0xff) {
- printf("sbicmsgin: sbic swallowed our message\n");
- break;
- }
+
+ tmpaddr++;
+
+ if ( recvlen ) {
+ /*
+ * Clear ACK, and wait for the interrupt for the next byte
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(regs, csr);
+ }
+ }
+
+ if ( msgaddr[0] == 0xff ) {
+ printf("sbicmsgin: sbic swallowed our message\n");
+ break;
+ }
+
#ifdef DEBUG
- if (sync_debug)
- printf("msgin done csr 0x%x asr 0x%x msg 0x%x\n",
- csr, asr, dev->sc_msg[0]);
-#endif
- /*
- * test whether this is a reply to our sync
- * request
- */
- if (MSG_ISIDENTIFY(dev->sc_msg[0])) {
- QPRINTF(("IFFY"));
-#if 0
- /* There is an implied load-ptrs here */
- sbic_load_ptrs(dev, regs, dev->target, dev->lun);
-#endif
- /* Got IFFY msg -- ack it */
- } else if (dev->sc_msg[0] == MSG_REJECT
- && dev->sc_sync[dev->target].state == SYNC_SENT) {
- QPRINTF(("REJECT of SYN"));
+ if ( sync_debug ) {
+ GET_SBIC_asr(regs, asr);
+ printf("msgin done csr 0x%x asr 0x%x msg 0x%x\n", csr, asr, msgaddr[0]);
+ }
+#endif
+ /*
+ * test whether this is a reply to our sync
+ * request
+ */
+ if ( MSG_ISIDENTIFY(msgaddr[0]) ) {
+
+ /*
+ * Got IFFY msg -- ack it
+ */
+ QPRINTF(("IFFY"));
+
+ } else
+ if ( msgaddr[0] == MSG_REJECT &&
+ dev->sc_sync[dev->target].state == SYNC_SENT) {
+
+ /*
+ * Target probably rejected our Sync negotiation.
+ */
+ QPRINTF(("REJECT of SYN"));
+
#ifdef DEBUG
- if (sync_debug)
- printf("target %d rejected sync, going async\n",
- dev->target);
+ if ( sync_debug )
+ printf("target %d rejected sync, going async\n", dev->target);
#endif
- dev->sc_sync[dev->target].period = sbic_min_period;
- dev->sc_sync[dev->target].offset = 0;
- dev->sc_sync[dev->target].state = SYNC_DONE;
- SET_SBIC_syn(regs,
- SBIC_SYN(dev->sc_sync[dev->target].offset,
- dev->sc_sync[dev->target].period));
- } else if ((dev->sc_msg[0] == MSG_REJECT)) {
- QPRINTF(("REJECT"));
- /*
- * we'll never REJECt a REJECT message..
- */
- } else if ((dev->sc_msg[0] == MSG_SAVE_DATA_PTR)) {
- QPRINTF(("MSG_SAVE_DATA_PTR"));
- /*
- * don't reject this either.
- */
- } else if ((dev->sc_msg[0] == MSG_DISCONNECT)) {
- QPRINTF(("DISCONNECT"));
+
+ dev->sc_sync[dev->target].period = sbic_min_period;
+ dev->sc_sync[dev->target].offset = 0;
+ dev->sc_sync[dev->target].state = SYNC_DONE;
+ SET_SBIC_syn(regs, SBIC_SYN(dev->sc_sync[dev->target].offset,
+ dev->sc_sync[dev->target].period));
+
+ } else
+ if ( msgaddr[0] == MSG_REJECT ) {
+
+ /*
+ * we'll never REJECt a REJECT message..
+ */
+ QPRINTF(("REJECT"));
+
+ } else
+ if ( msgaddr[0] == MSG_SAVE_DATA_PTR ) {
+
+ /*
+ * don't reject this either.
+ */
+ QPRINTF(("MSG_SAVE_DATA_PTR"));
+
+ } else
+ if ( msgaddr[0] == MSG_RESTORE_PTR ) {
+
+ /*
+ * don't reject this either.
+ */
+ QPRINTF(("MSG_RESTORE_PTR"));
+
+ } else
+ if ( msgaddr[0] == MSG_DISCONNECT ) {
+
+ /*
+ * Target is disconnecting...
+ */
+ QPRINTF(("DISCONNECT"));
+
#ifdef DEBUG
- if( reselect_debug>1 && dev->sc_msg[0] == MSG_DISCONNECT )
- printf("sbicmsgin: got disconnect msg %s\n",
- (dev->sc_flags & SBICF_ICMD)?"rejecting":"");
-#endif
- if( dev->sc_flags & SBICF_ICMD ) {
- /* We're in immediate mode. Prevent disconnects. */
- /* prepare to reject the message, NACK */
- SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
- WAIT_CIP(regs);
- }
- } else if (dev->sc_msg[0] == MSG_CMD_COMPLETE ) {
- QPRINTF(("CMD_COMPLETE"));
- /* !! KLUDGE ALERT !! quite a few drives don't seem to
- * really like the current way of sending the
- * sync-handshake together with the ident-message, and
- * they react by sending command-complete and
- * disconnecting right after returning the valid sync
- * handshake. So, all I can do is reselect the drive,
- * and hope it won't disconnect again. I don't think
- * this is valid behavior, but I can't help fixing a
- * problem that apparently exists.
- *
- * Note: we should not get here on `normal' command
- * completion, as that condition is handled by the
- * high-level sel&xfer resume command used to walk
- * thru status/cc-phase.
- */
+ if ( reselect_debug > 1 && msgaddr[0] == MSG_DISCONNECT )
+ printf("sbicmsgin: got disconnect msg %s\n",
+ (dev->sc_flags & SBICF_ICMD) ? "rejecting" : "");
+#endif
+
+ if ( dev->sc_flags & SBICF_ICMD ) {
+ /*
+ * We're in immediate mode. Prevent disconnects.
+ * prepare to reject the message, NACK
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
+ WAIT_CIP(regs);
+ }
+
+ } else
+ if ( msgaddr[0] == MSG_CMD_COMPLETE ) {
+
+ /*
+ * !! KLUDGE ALERT !! quite a few drives don't seem to
+ * really like the current way of sending the
+ * sync-handshake together with the ident-message, and
+ * they react by sending command-complete and
+ * disconnecting right after returning the valid sync
+ * handshake. So, all I can do is reselect the drive,
+ * and hope it won't disconnect again. I don't think
+ * this is valid behavior, but I can't help fixing a
+ * problem that apparently exists.
+ *
+ * Note: we should not get here on `normal' command
+ * completion, as that condition is handled by the
+ * high-level sel&xfer resume command used to walk
+ * thru status/cc-phase.
+ */
+ QPRINTF(("CMD_COMPLETE"));
#ifdef DEBUG
- if (sync_debug)
- printf ("GOT MSG %d! target %d acting weird.."
- " waiting for disconnect...\n",
- dev->sc_msg[0], dev->target);
-#endif
- /* Check to see if sbic is handling this */
- GET_SBIC_asr(regs, asr);
- if(asr & SBIC_ASR_BSY)
- return SBIC_STATE_RUNNING;
-
- /* Let's try this: Assume it works and set status to 00 */
- dev->sc_stat[0] = 0;
- } else if (dev->sc_msg[0] == MSG_EXT_MESSAGE
- && tmpaddr == &dev->sc_msg[1]) {
- QPRINTF(("ExtMSG\n"));
- /* Read in whole extended message */
- SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
- SBIC_WAIT(regs, SBIC_ASR_INT, 0);
- GET_SBIC_asr(regs, asr);
- GET_SBIC_csr(regs, csr);
- QPRINTF(("CLR ACK asr %02x, csr %02x\n", asr, csr));
- RECV_BYTE(regs, *tmpaddr);
- /* Wait for command completion IRQ */
- SBIC_WAIT(regs, SBIC_ASR_INT, 0);
- recvlen = *tmpaddr++;
- QPRINTF(("Recving ext msg, asr %02x csr %02x len %02x\n",
- asr, csr, recvlen));
- } else if (dev->sc_msg[0] == MSG_EXT_MESSAGE && dev->sc_msg[1] == 3
- && dev->sc_msg[2] == MSG_SYNC_REQ) {
- QPRINTF(("SYN"));
- dev->sc_sync[dev->target].period =
- sbicfromscsiperiod(dev,
- regs, dev->sc_msg[3]);
- dev->sc_sync[dev->target].offset = dev->sc_msg[4];
- dev->sc_sync[dev->target].state = SYNC_DONE;
- SET_SBIC_syn(regs,
- SBIC_SYN(dev->sc_sync[dev->target].offset,
- dev->sc_sync[dev->target].period));
- printf("%s: target %d now synchronous,"
- " period=%dns, offset=%d.\n",
- dev->sc_dev.dv_xname, dev->target,
- dev->sc_msg[3] * 4, dev->sc_msg[4]);
- } else {
+ if ( sync_debug )
+ printf ("GOT MSG %d! target %d acting weird.."
+ " waiting for disconnect...\n", msgaddr[0], dev->target);
+#endif
+
+ /*
+ * Check to see if sbic is handling this
+ */
+ GET_SBIC_asr(regs, asr);
+
+ /*
+ * XXXSCW: I'm not convinced of this, we haven't negated ACK yet...
+ */
+ if ( asr & SBIC_ASR_BSY )
+ return SBIC_STATE_RUNNING;
+
+ /*
+ * Let's try this: Assume it works and set status to 00
+ */
+ dev->sc_stat[0] = 0;
+
+ } else
+ if ( msgaddr[0] == MSG_EXT_MESSAGE && tmpaddr == &(msgaddr[1]) ) {
+
+ /*
+ * Target is sending us an extended message. We'll assume it's
+ * the response to our Sync. negotiation.
+ */
+ QPRINTF(("ExtMSG\n"));
+
+ /*
+ * Read in whole extended message. First, negate ACK to accept
+ * the MSG_EXT_MESSAGE byte...
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+
+ /*
+ * Wait for the interrupt for the next byte (length)
+ */
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(regs, csr);
+
+#ifdef DEBUG
+ QPRINTF(("CLR ACK csr %02x\n", csr));
+#endif
+
+ /*
+ * Read the length byte
+ */
+ RECV_BYTE(regs, *tmpaddr);
+
+ /*
+ * Wait for command completion IRQ
+ */
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ GET_SBIC_csr(regs, csr);
+
+ /*
+ * Reload the loop counter
+ */
+ recvlen = *tmpaddr++;
+
+ QPRINTF(("Recving ext msg, csr %02x len %02x\n", csr, recvlen));
+
+ } else
+ if ( msgaddr[0] == MSG_EXT_MESSAGE && msgaddr[1] == 3 &&
+ msgaddr[2] == MSG_SYNC_REQ ) {
+
+ /*
+ * We've received the complete Extended Message Sync. Request...
+ */
+ QPRINTF(("SYN"));
+
+ /*
+ * Compute the required Transfer Period for the WD chip...
+ */
+ dev->sc_sync[dev->target].period = sbicfromscsiperiod(dev, msgaddr[3]);
+ dev->sc_sync[dev->target].offset = msgaddr[4];
+ dev->sc_sync[dev->target].state = SYNC_DONE;
+
+ /*
+ * Put the WD chip in synchronous mode
+ */
+ SET_SBIC_syn(regs, SBIC_SYN(dev->sc_sync[dev->target].offset,
+ dev->sc_sync[dev->target].period));
+
+ printf("%s: target %d now synchronous, period=%dns, offset=%d.\n",
+ dev->sc_dev.dv_xname, dev->target,
+ msgaddr[3] * 4, msgaddr[4]);
+
+ } else {
+
+ /*
+ * We don't support whatever this message is...
+ */
#ifdef DEBUG
- if (sbic_debug || sync_debug)
- printf ("sbicmsgin: Rejecting message 0x%02x\n",
- dev->sc_msg[0]);
-#endif
- /* prepare to reject the message, NACK */
- SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
- WAIT_CIP(regs);
- }
- /* Clear ACK */
- WAIT_CIP(regs);
- GET_SBIC_asr(regs, asr);
- GET_SBIC_csr(regs, csr);
- QPRINTF(("sbicmsgin pre CLR_ACK (csr,asr)=(%02x,%02x)%d\n",
- csr, asr, recvlen));
- SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
- SBIC_WAIT(regs, SBIC_ASR_INT, 0);
- }
-#if 0
- while((csr == SBIC_CSR_MSGIN_W_ACK)
- || (SBIC_PHASE(csr) == MESG_IN_PHASE));
-#else
- while (recvlen>0);
-#endif
-
- QPRINTF(("sbicmsgin finished: csr %02x, asr %02x\n",csr, asr));
-
- /* Should still have one CSR to read */
- return SBIC_STATE_RUNNING;
+ if ( sbic_debug || sync_debug )
+ printf ("sbicmsgin: Rejecting message 0x%02x\n", msgaddr[0]);
+#endif
+
+ /*
+ * prepare to reject the message, NACK
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_SET_ATN);
+ WAIT_CIP(regs);
+ }
+
+ /*
+ * Negate ACK to complete the transfer
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+
+ /*
+ * Wait for the interrupt for the next byte, or phase change.
+ * Only read the CSR if we have more data to transfer.
+ * XXXSCW: We should really verify that we're still in MSG IN phase
+ * before blindly going back around this loop, but that would mean
+ * we read the CSR... <sigh>
+ */
+ SBIC_WAIT(regs, SBIC_ASR_INT, 0);
+ if ( recvlen > 0 )
+ GET_SBIC_csr(regs, csr);
+
+ } while ( recvlen > 0 );
+
+ /*
+ * Should still have one CSR to read
+ */
+ return SBIC_STATE_RUNNING;
}
/*
* sbicnextstate()
* return:
- * 0 == done
- * 1 == working
- * 2 == disconnected
- * -1 == error
+ * 0 == done
+ * 1 == working
+ * 2 == disconnected
+ * -1 == error
*/
int
sbicnextstate(dev, csr, asr)
- struct sbic_softc *dev;
- u_char csr, asr;
+ struct sbic_softc *dev;
+ u_char csr,
+ asr;
{
- sbic_regmap_p regs;
- struct dma_chain *df, *dl;
- struct sbic_acb *acb;
- int i, newtarget, newlun, wait;
- unsigned tcnt;
-
- regs = dev->sc_sbicp;
- acb = dev->sc_nexus;
-
- QPRINTF(("next[%02x,%02x]",asr,csr));
-
- switch (csr) {
- case SBIC_CSR_XFERRED|CMD_PHASE:
- case SBIC_CSR_MIS|CMD_PHASE:
- case SBIC_CSR_MIS_1|CMD_PHASE:
- case SBIC_CSR_MIS_2|CMD_PHASE:
- sbic_save_ptrs(dev, regs, dev->target, dev->lun);
- if (sbicxfstart(regs, acb->clen, CMD_PHASE, sbic_cmd_wait))
- if (sbicxfout(regs, acb->clen,
- &acb->cmd, CMD_PHASE))
- goto abort;
- break;
-
- case SBIC_CSR_XFERRED|STATUS_PHASE:
- case SBIC_CSR_MIS|STATUS_PHASE:
- case SBIC_CSR_MIS_1|STATUS_PHASE:
- case SBIC_CSR_MIS_2|STATUS_PHASE:
- /*
- * this should be the normal i/o completion case.
- * get the status & cmd complete msg then let the
- * device driver look at what happened.
- */
- sbicxfdone(dev,regs,dev->target);
- /*
- * check for overlapping cache line, flush if so
- */
-#ifdef M68040
- if (dev->sc_flags & SBICF_DCFLUSH) {
-#if 0
- printf("sbic: 68040 DMA cache flush needs fixing? %x:%x\n",
- dev->sc_xs->data, dev->sc_xs->datalen);
-#endif
- }
-#endif
+ sbic_regmap_p regs = dev->sc_sbicp;
+ struct sbic_acb *acb = dev->sc_nexus;
+
+ QPRINTF(("next[%02x,%02x]: ",asr,csr));
+
+ switch (csr) {
+
+ case SBIC_CSR_XFERRED | CMD_PHASE:
+ case SBIC_CSR_MIS | CMD_PHASE:
+ case SBIC_CSR_MIS_1 | CMD_PHASE:
+ case SBIC_CSR_MIS_2 | CMD_PHASE:
+ {
+ if ( sbicxfout(regs, acb->clen, &acb->cmd) )
+ goto abort;
+ }
+ break;
+
+ case SBIC_CSR_XFERRED | STATUS_PHASE:
+ case SBIC_CSR_MIS | STATUS_PHASE:
+ case SBIC_CSR_MIS_1 | STATUS_PHASE:
+ case SBIC_CSR_MIS_2 | STATUS_PHASE:
+ {
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+
+ /*
+ * this should be the normal i/o completion case.
+ * get the status & cmd complete msg then let the
+ * device driver look at what happened.
+ */
+ sbicxfdone(dev);
+
#ifdef DEBUG
- if( data_pointer_debug > 1 )
- printf("next dmastop: %d(%x:%x)\n",
- dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
-#endif
- dev->sc_dmastop(dev); /* was dmafree */
- if (acb->flags & ACB_BBUF) {
- if ((u_char *)kvtop(acb->sc_dmausrbuf) != acb->sc_usrbufpa)
- printf("%s: WARNING - buffer mapping changed %x->%x\n",
- dev->sc_dev.dv_xname, acb->sc_usrbufpa,
- kvtop(acb->sc_dmausrbuf));
+ dev->sc_dmatimo = 0;
+ if ( data_pointer_debug > 1 )
+ printf("next dmastop: %d(%x:%x)\n", dev->target,
+ dev->sc_cur->dc_addr,
+ dev->sc_tcnt);
+#endif
+ /*
+ * Stop the DMA chip
+ */
+ dev->sc_dmastop(dev);
+
+ dev->sc_flags &= ~(SBICF_INDMA | SBICF_DCFLUSH);
+
+ /*
+ * Indicate to the upper layers that the command is done
+ */
+ sbic_scsidone(acb, dev->sc_stat[0]);
+
+ return SBIC_STATE_DONE;
+ }
+
+ case SBIC_CSR_XFERRED | DATA_OUT_PHASE:
+ case SBIC_CSR_XFERRED | DATA_IN_PHASE:
+ case SBIC_CSR_MIS | DATA_OUT_PHASE:
+ case SBIC_CSR_MIS | DATA_IN_PHASE:
+ case SBIC_CSR_MIS_1 | DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_1 | DATA_IN_PHASE:
+ case SBIC_CSR_MIS_2 | DATA_OUT_PHASE:
+ case SBIC_CSR_MIS_2 | DATA_IN_PHASE:
+ {
+ /*
+ * Verify that we expected to transfer data...
+ */
+ if ( acb->sc_kv.dc_count <= 0 ) {
+ printf("next: DATA phase with xfer count == %d, asr:0x%02x csr:0x%02x\n",
+ acb->sc_kv.dc_count, asr, csr);
+ goto abort;
+ }
+
+ /*
+ * Should we transfer using PIO or DMA ?
+ */
+ if ( dev->sc_xs->flags & SCSI_POLL || dev->sc_flags & SBICF_ICMD ||
+ acb->sc_dmacmd == 0 ) {
+
+ /*
+ * Do PIO transfer
+ */
+ int i;
+
#ifdef DEBUG
- if(data_pointer_debug)
- printf("sbicgo:copying %x bytes from target %d bounce %x\n",
- acb->sc_dmausrlen,
- dev->target,
- kvtop(dev->sc_tinfo[dev->target].bounce));
-#endif
- bcopy(dev->sc_tinfo[dev->target].bounce,
- acb->sc_dmausrbuf,
- acb->sc_dmausrlen);
- }
- dev->sc_flags &= ~(SBICF_INDMA | SBICF_DCFLUSH);
- sbic_scsidone(acb, dev->sc_stat[0]);
- return SBIC_STATE_DONE;
-
- case SBIC_CSR_XFERRED|DATA_OUT_PHASE:
- case SBIC_CSR_XFERRED|DATA_IN_PHASE:
- case SBIC_CSR_MIS|DATA_OUT_PHASE:
- case SBIC_CSR_MIS|DATA_IN_PHASE:
- case SBIC_CSR_MIS_1|DATA_OUT_PHASE:
- case SBIC_CSR_MIS_1|DATA_IN_PHASE:
- case SBIC_CSR_MIS_2|DATA_OUT_PHASE:
- case SBIC_CSR_MIS_2|DATA_IN_PHASE:
- if( dev->sc_xs->flags & SCSI_POLL || dev->sc_flags & SBICF_ICMD
- || acb->sc_dmacmd == 0 ) {
- /* Do PIO */
- SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
- if (acb->sc_kv.dc_count <= 0) {
- printf("sbicnextstate:xfer count %d asr%x csr%x\n",
- acb->sc_kv.dc_count, asr, csr);
- goto abort;
- }
- wait = sbic_data_wait;
- if( sbicxfstart(regs,
- acb->sc_kv.dc_count,
- SBIC_PHASE(csr), wait))
- if( SBIC_PHASE(csr) == DATA_IN_PHASE )
- /* data in? */
- i=sbicxfin(regs,
- acb->sc_kv.dc_count,
- acb->sc_kv.dc_addr);
- else
- i=sbicxfout(regs,
- acb->sc_kv.dc_count,
- acb->sc_kv.dc_addr,
- SBIC_PHASE(csr));
- acb->sc_kv.dc_addr +=
- (acb->sc_kv.dc_count - i);
- acb->sc_kv.dc_count = i;
- } else {
- /*
- * do scatter-gather dma
- * hacking the controller chip, ouch..
- */
- SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI |
- SBIC_MACHINE_DMA_MODE);
- /*
- * set next dma addr and dec count
- */
-#if 0
- SBIC_TC_GET(regs, tcnt);
- dev->sc_cur->dc_count -= ((dev->sc_tcnt - tcnt) >> 1);
- dev->sc_cur->dc_addr += (dev->sc_tcnt - tcnt);
- dev->sc_tcnt = acb->sc_tcnt = tcnt;
-#else
- sbic_save_ptrs(dev, regs, dev->target, dev->lun);
- sbic_load_ptrs(dev, regs, dev->target, dev->lun);
-#endif
+ if ( data_pointer_debug > 1 )
+ printf("next PIO: %d(%x:%x)\n", dev->target,
+ acb->sc_kv.dc_addr,
+ acb->sc_kv.dc_count);
+#endif
+
+ if ( SBIC_PHASE(csr) == DATA_IN_PHASE )
+ /*
+ * data in
+ */
+ i = sbicxfin(regs, acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr);
+ else
+ /*
+ * data out
+ */
+ i = sbicxfout(regs, acb->sc_kv.dc_count,
+ acb->sc_kv.dc_addr);
+
+ acb->sc_kv.dc_addr += (acb->sc_kv.dc_count - i);
+ acb->sc_kv.dc_count = i;
+
+ /*
+ * Update current count...
+ */
+ acb->sc_tcnt = dev->sc_tcnt = i;
+
+ dev->sc_flags &= ~SBICF_INDMA;
+
+ } else {
+
+ /*
+ * Do DMA transfer
+ * set next dma addr and dec count
+ */
+ sbic_save_ptrs(dev);
+ sbic_load_ptrs(dev);
+
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI |
+ SBIC_MACHINE_DMA_MODE);
+
#ifdef DEBUG
- if( data_pointer_debug > 1 )
- printf("next dmanext: %d(%x:%x)\n",
- dev->target,dev->sc_cur->dc_addr,
- dev->sc_tcnt);
-#endif
- dev->sc_tcnt = dev->sc_dmanext(dev);
- SBIC_TC_PUT(regs, (unsigned)dev->sc_tcnt);
- SET_SBIC_cmd(regs, SBIC_CMD_XFER_INFO);
- dev->sc_flags |= SBICF_INDMA;
- }
- break;
-
- case SBIC_CSR_XFERRED|MESG_IN_PHASE:
- case SBIC_CSR_MIS|MESG_IN_PHASE:
- case SBIC_CSR_MIS_1|MESG_IN_PHASE:
- case SBIC_CSR_MIS_2|MESG_IN_PHASE:
- return sbicmsgin(dev);
-
- case SBIC_CSR_MSGIN_W_ACK:
- SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK); /* Dunno what I'm ACKing */
- printf("Acking unknown msgin CSR:%02x",csr);
- break;
-
- case SBIC_CSR_XFERRED|MESG_OUT_PHASE:
- case SBIC_CSR_MIS|MESG_OUT_PHASE:
- case SBIC_CSR_MIS_1|MESG_OUT_PHASE:
- case SBIC_CSR_MIS_2|MESG_OUT_PHASE:
+ dev->sc_dmatimo = 1;
+ if ( data_pointer_debug > 1 )
+ printf("next DMA: %d(%x:%x)\n", dev->target,
+ dev->sc_cur->dc_addr,
+ dev->sc_tcnt);
+#endif
+ /*
+ * Start the DMA chip going
+ */
+ dev->sc_tcnt = dev->sc_dmanext(dev);
+
+ /*
+ * Tell the WD chip how much to transfer this time around
+ */
+ SBIC_TC_PUT(regs, (unsigned)dev->sc_tcnt);
+
+ /*
+ * Start the transfer
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_XFER_INFO);
+
+ /*
+ * Indicate that we're in DMA mode
+ */
+ dev->sc_flags |= SBICF_INDMA;
+ }
+ }
+ break;
+
+ case SBIC_CSR_XFERRED | MESG_IN_PHASE:
+ case SBIC_CSR_MIS | MESG_IN_PHASE:
+ case SBIC_CSR_MIS_1 | MESG_IN_PHASE:
+ case SBIC_CSR_MIS_2 | MESG_IN_PHASE:
+ {
+ sbic_save_ptrs(dev);
+
+ /*
+ * Handle a single message in...
+ */
+ return sbicmsgin(dev);
+ }
+
+ case SBIC_CSR_MSGIN_W_ACK:
+ {
+ /*
+ * We should never see this since it's handled in 'sbicmsgin()'
+ * but just for the sake of paranoia...
+ */
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK); /* Dunno what I'm ACKing */
+ printf("Acking unknown msgin CSR:%02x",csr);
+ }
+ break;
+
+ case SBIC_CSR_XFERRED | MESG_OUT_PHASE:
+ case SBIC_CSR_MIS | MESG_OUT_PHASE:
+ case SBIC_CSR_MIS_1 | MESG_OUT_PHASE:
+ case SBIC_CSR_MIS_2 | MESG_OUT_PHASE:
+ {
+ /*
+ * We only ever handle a message out phase here for sending a
+ * REJECT message.
+ */
+ sbic_save_ptrs(dev);
+
#ifdef DEBUG
- if (sync_debug)
- printf ("sending REJECT msg to last msg.\n");
+ if (sync_debug)
+ printf ("sending REJECT msg to last msg.\n");
#endif
- sbic_save_ptrs(dev, regs, dev->target, dev->lun);
- /*
- * should only get here on reject,
- * since it's always US that
- * initiate a sync transfer
- */
- SEND_BYTE(regs, MSG_REJECT);
- WAIT_CIP(regs);
- if( asr & (SBIC_ASR_BSY|SBIC_ASR_LCI|SBIC_ASR_CIP) )
- printf("next: REJECT sent asr %02x\n", asr);
- return SBIC_STATE_RUNNING;
-
- case SBIC_CSR_DISC:
- case SBIC_CSR_DISC_1:
- dev->sc_flags &= ~(SBICF_INDMA|SBICF_SELECTED);
-
- /* Try to schedule another target */
+ SEND_BYTE(regs, MSG_REJECT);
+ WAIT_CIP(regs);
+ }
+ break;
+
+ case SBIC_CSR_DISC:
+ case SBIC_CSR_DISC_1:
+ {
+ /*
+ * Try to schedule another target
+ */
+ sbic_save_ptrs(dev);
+
+ dev->sc_flags &= ~SBICF_SELECTED;
+
#ifdef DEBUG
- if(reselect_debug>1)
- printf("sbicnext target %d disconnected\n", dev->target);
+ if ( reselect_debug > 1 )
+ printf("sbicnext target %d disconnected\n", dev->target);
#endif
- TAILQ_INSERT_HEAD(&dev->nexus_list, acb, chain);
- ++dev->sc_tinfo[dev->target].dconns;
- dev->sc_nexus = NULL;
- dev->sc_xs = NULL;
-
- if( acb->xs->flags & SCSI_POLL
- || (dev->sc_flags & SBICF_ICMD)
- || !sbic_parallel_operations )
- return SBIC_STATE_DISCONNECT;
- sbic_sched(dev);
- return SBIC_STATE_DISCONNECT;
-
- case SBIC_CSR_RSLT_NI:
- case SBIC_CSR_RSLT_IFY:
- GET_SBIC_rselid(regs, newtarget);
- /* check SBIC_RID_SIV? */
- newtarget &= SBIC_RID_MASK;
- if (csr == SBIC_CSR_RSLT_IFY) {
- /* Read IFY msg to avoid lockup */
- GET_SBIC_data(regs, newlun);
- WAIT_CIP(regs);
- newlun &= SBIC_TLUN_MASK;
- } else {
- /* Need to get IFY message */
- for (newlun = 256; newlun; --newlun) {
- GET_SBIC_asr(regs, asr);
- if (asr & SBIC_ASR_INT)
- break;
- delay(1);
- }
- newlun = 0; /* XXXX */
- if ((asr & SBIC_ASR_INT) == 0) {
+
+ TAILQ_INSERT_HEAD(&dev->nexus_list, acb, chain);
+
+ ++dev->sc_tinfo[dev->target].dconns;
+
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+
+ if ( acb->xs->flags & SCSI_POLL || dev->sc_flags & SBICF_ICMD ||
+ !sbic_parallel_operations )
+ return SBIC_STATE_DISCONNECT;
+
+ QPRINTF(("sbicnext: calling sbic_sched\n"));
+
+ sbic_sched(dev);
+
+ QPRINTF(("sbicnext: sbic_sched returned\n"));
+
+ return SBIC_STATE_DISCONNECT;
+ }
+
+ case SBIC_CSR_RSLT_NI:
+ case SBIC_CSR_RSLT_IFY:
+ {
+ /*
+ * A reselection.
+ * Note that since we don't enable Advanced Features (assuming
+ * the WD chip is at least the 'A' revision), we're only ever
+ * likely to see the 'SBIC_CSR_RSLT_NI' status. But for the
+ * hell of it, we'll handle it anyway, for all the extra code
+ * it needs...
+ */
+ u_char newtarget,
+ newlun;
+
+ GET_SBIC_rselid(regs, newtarget);
+
+ /*
+ * check SBIC_RID_SIV?
+ */
+ newtarget &= SBIC_RID_MASK;
+
+ if ( csr == SBIC_CSR_RSLT_IFY ) {
+
+ /*
+ * Read Identify msg to avoid lockup
+ */
+ GET_SBIC_data(regs, newlun);
+ WAIT_CIP(regs);
+ newlun &= SBIC_TLUN_MASK;
+
+ } else {
+
+ /*
+ * Need to read Identify message the hard way, assuming
+ * the target even sends us one...
+ */
+ for (newlun = 255; newlun; --newlun) {
+ GET_SBIC_asr(regs, asr);
+ if (asr & SBIC_ASR_INT)
+ break;
+ delay(1);
+ }
+
+ /*
+ * If we didn't get an interrupt, somethink's up
+ */
+ if ( (asr & SBIC_ASR_INT) == 0 ) {
#ifdef DEBUG
- if (reselect_debug)
- printf("RSLT_NI - no IFFY message? asr %x\n", asr);
-#endif
- } else {
- GET_SBIC_csr(regs,csr);
- if (csr == SBIC_CSR_MIS|MESG_IN_PHASE ||
- csr == SBIC_CSR_MIS_1|MESG_IN_PHASE ||
- csr == SBIC_CSR_MIS_2|MESG_IN_PHASE) {
- sbicmsgin(dev);
- newlun = dev->sc_msg[0] & 7;
- } else {
- printf("RSLT_NI - not MESG_IN_PHASE %x\n",
- csr);
- }
- }
- }
+ if ( reselect_debug )
+ printf("RSLT_NI - no IFFY message? asr %x\n", asr);
+#endif
+ newlun = 0; /* XXXX */
+
+ } else {
+ /*
+ * We got an interrupt, verify that it's a change to
+ * message in phase, and if so read the message.
+ */
+ GET_SBIC_csr(regs,csr);
+
+ if ( csr == SBIC_CSR_MIS | MESG_IN_PHASE ||
+ csr == SBIC_CSR_MIS_1 | MESG_IN_PHASE ||
+ csr == SBIC_CSR_MIS_2 | MESG_IN_PHASE ) {
+ /*
+ * Yup, gone to message in. Fetch the target LUN
+ */
+ sbicmsgin(dev);
+ newlun = dev->sc_msg[0] & 0x07;
+
+ } else {
+ /*
+ * Whoops! Target didn't go to message in phase!!
+ */
+ printf("RSLT_NI - not MESG_IN_PHASE %x\n", csr);
+ newlun = 0; /* XXXSCW */
+ }
+ }
+ }
+
+ /*
+ * Ok, we have the identity of the reselecting target.
+ */
#ifdef DEBUG
- if(reselect_debug>1 || (reselect_debug && csr==SBIC_CSR_RSLT_NI))
- printf("sbicnext: reselect %s from targ %d lun %d\n",
- csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY",
- newtarget, newlun);
-#endif
- if (dev->sc_nexus) {
+ if ( reselect_debug > 1 ||
+ (reselect_debug && csr == SBIC_CSR_RSLT_NI) ) {
+ printf("sbicnext: reselect %s from targ %d lun %d\n",
+ csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY", newtarget, newlun);
+ }
+#endif
+
+ if ( dev->sc_nexus ) {
+ /*
+ * Whoops! We've been reselected with an command in progress!
+ * The best we can do is to put the current command back on the
+ * ready list and hope for the best.
+ */
#ifdef DEBUG
- if (reselect_debug > 1)
- printf("%s: reselect %s with active command\n",
- dev->sc_dev.dv_xname,
- csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY");
-#ifdef DDB
-/* Debugger();*/
-#endif
-#endif
- TAILQ_INSERT_HEAD(&dev->ready_list, dev->sc_nexus, chain);
- dev->sc_tinfo[dev->target].lubusy &= ~(1 << dev->lun);
- }
- /* Reload sync values for this target */
- if (dev->sc_sync[newtarget].state == SYNC_DONE)
- SET_SBIC_syn(regs, SBIC_SYN (dev->sc_sync[newtarget].offset,
- dev->sc_sync[newtarget].period));
- else
- SET_SBIC_syn(regs, SBIC_SYN (0, sbic_min_period));
- for (acb = dev->nexus_list.tqh_first; acb;
- acb = acb->chain.tqe_next) {
- if (acb->xs->sc_link->target != newtarget ||
- acb->xs->sc_link->lun != newlun)
- continue;
- TAILQ_REMOVE(&dev->nexus_list, acb, chain);
- dev->sc_nexus = acb;
- dev->sc_xs = acb->xs;
- dev->sc_flags |= SBICF_SELECTED;
- dev->target = newtarget;
- dev->lun = newlun;
- break;
- }
- if (acb == NULL) {
- printf("%s: reselect %s targ %d not in nexus_list %x\n",
- dev->sc_dev.dv_xname,
- csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY", newtarget,
- &dev->nexus_list.tqh_first);
- panic("bad reselect in sbic");
- }
- if (csr == SBIC_CSR_RSLT_IFY)
- SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
- break;
-
- default:
+ if ( reselect_debug > 1 ) {
+ printf("%s: reselect %s with active command\n",
+ dev->sc_dev.dv_xname,
+ csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY");
+ }
+#endif
+
+ TAILQ_INSERT_HEAD(&dev->ready_list, dev->sc_nexus, chain);
+
+ dev->sc_tinfo[dev->target].lubusy &= ~(1 << dev->lun);
+
+ dev->sc_nexus = NULL;
+ dev->sc_xs = NULL;
+ }
+
+ /*
+ * Reload sync values for this target
+ */
+ if ( dev->sc_sync[newtarget].state == SYNC_DONE )
+ SET_SBIC_syn(regs, SBIC_SYN (dev->sc_sync[newtarget].offset,
+ dev->sc_sync[newtarget].period));
+ else
+ SET_SBIC_syn(regs, SBIC_SYN (0, sbic_min_period));
+
+ /*
+ * Loop through the nexus list until we find the saved entry
+ * for the reselecting target...
+ */
+ for (acb = dev->nexus_list.tqh_first; acb;
+ acb = acb->chain.tqe_next) {
+
+ if ( acb->xs->sc_link->target == newtarget &&
+ acb->xs->sc_link->lun == newlun) {
+ /*
+ * We've found the saved entry. Dequeue it, and
+ * make it current again.
+ */
+ TAILQ_REMOVE(&dev->nexus_list, acb, chain);
+
+ dev->sc_nexus = acb;
+ dev->sc_xs = acb->xs;
+ dev->sc_flags |= SBICF_SELECTED;
+ dev->target = newtarget;
+ dev->lun = newlun;
+ break;
+ }
+ }
+
+ if ( acb == NULL ) {
+ printf("%s: reselect %s targ %d not in nexus_list %x\n",
+ dev->sc_dev.dv_xname,
+ csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY", newtarget,
+ &dev->nexus_list.tqh_first);
+ panic("bad reselect in sbic");
+ }
+
+ if ( csr == SBIC_CSR_RSLT_IFY )
+ SET_SBIC_cmd(regs, SBIC_CMD_CLR_ACK);
+ }
+ break;
+
+ default:
abort:
- /*
- * Something unexpected happened -- deal with it.
- */
- printf("sbicnextstate: aborting csr %02x asr %02x\n", csr, asr);
+ {
+ /*
+ * Something unexpected happened -- deal with it.
+ */
+ printf("next: aborting asr 0x%02x csr 0x%02x\n", asr, csr);
+
#ifdef DDB
- Debugger();
+ Debugger();
#endif
+
#ifdef DEBUG
- if( data_pointer_debug > 1 )
- printf("next dmastop: %d(%x:%x)\n",
- dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
-#endif
- dev->sc_dmastop(dev);
- sbicerror(dev, regs, csr);
- sbicabort(dev, regs, "next");
- if (dev->sc_flags & SBICF_INDMA) {
- /*
- * check for overlapping cache line, flush if so
- */
-#ifdef M68040
- if (dev->sc_flags & SBICF_DCFLUSH) {
-#if 0
- printf("sibc: 68040 DMA cache flush needs fixing? %x:%x\n",
- dev->sc_xs->data, dev->sc_xs->datalen);
-#endif
- }
+ dev->sc_dmatimo = 0;
+ if ( data_pointer_debug > 1 )
+ printf("next dmastop: %d(%x:%x)\n", dev->target,
+ dev->sc_cur->dc_addr,
+ dev->sc_tcnt);
#endif
- dev->sc_flags &=
- ~(SBICF_INDMA | SBICF_DCFLUSH);
+
+ dev->sc_dmastop(dev);
+ SET_SBIC_control(regs, SBIC_CTL_EDI | SBIC_CTL_IDI);
+ if ( dev->sc_xs ) sbicerror(dev, csr);
+ sbicabort(dev, "next");
+
+ if ( dev->sc_flags & SBICF_INDMA ) {
+ dev->sc_flags &= ~(SBICF_INDMA | SBICF_DCFLUSH);
+
#ifdef DEBUG
- if( data_pointer_debug > 1 )
- printf("next dmastop: %d(%x:%x)\n",
- dev->target,dev->sc_cur->dc_addr,dev->sc_tcnt);
+ dev->sc_dmatimo = 0;
+ if ( data_pointer_debug > 1 )
+ printf("next dmastop: %d(%x:%x)\n", dev->target,
+ dev->sc_cur->dc_addr,
+ dev->sc_tcnt);
#endif
- dev->sc_dmastop(dev);
- sbic_scsidone(acb, -1);
- }
- return SBIC_STATE_ERROR;
- }
+ sbic_scsidone(acb, -1);
+ }
+
+ return SBIC_STATE_ERROR;
+ }
+ }
- return(SBIC_STATE_RUNNING);
+ return(SBIC_STATE_RUNNING);
}
/*
* Check if DMA can not be used with specified buffer
*/
-
int
sbiccheckdmap(bp, len, mask)
- void *bp;
- u_long len, mask;
+ void *bp;
+ u_long len,
+ mask;
{
- u_char *buffer;
- u_long phy_buf;
- u_long phy_len;
-
- buffer = bp;
-
- if (len == 0)
- return(0);
-
- while (len) {
- phy_buf = kvtop(buffer);
- if (len < (phy_len = NBPG - ((int) buffer & PGOFSET)))
- phy_len = len;
- if (phy_buf & mask)
- return(1);
- buffer += phy_len;
- len -= phy_len;
- }
- return(0);
+ u_char *buffer;
+ u_long phy_buf;
+ u_long phy_len;
+
+ buffer = bp;
+
+ if ( len == 0 )
+ return(1);
+
+ while ( len ) {
+
+ phy_buf = kvtop(buffer);
+ phy_len = NBPG - ((int) buffer & PGOFSET);
+
+ if ( len < phy_len )
+ phy_len = len;
+
+ if ( phy_buf & mask )
+ return(1);
+
+ buffer += phy_len;
+ len -= phy_len;
+ }
+
+ return(0);
}
int
-sbictoscsiperiod(dev, regs, a)
- struct sbic_softc *dev;
- sbic_regmap_p regs;
- int a;
+sbictoscsiperiod(dev, a)
+ struct sbic_softc *dev;
+ int a;
{
- unsigned int fs;
-
- /*
- * cycle = DIV / (2*CLK)
- * DIV = FS+2
- * best we can do is 200ns at 20Mhz, 2 cycles
- */
-
- GET_SBIC_myid(regs,fs);
- fs = (fs >>6) + 2; /* DIV */
- fs = (fs * 10000) / (dev->sc_clkfreq<<1); /* Cycle, in ns */
- if (a < 2) a = 8; /* map to Cycles */
- return ((fs*a)>>2); /* in 4 ns units */
+ unsigned int fs;
+
+ /*
+ * cycle = DIV / (2 * CLK)
+ * DIV = FS + 2
+ * best we can do is 200ns at 20Mhz, 2 cycles
+ */
+
+ GET_SBIC_myid(dev->sc_sbicp, fs);
+
+ fs = (fs >> 6) + 2; /* DIV */
+
+ fs = (fs * 10000) / (dev->sc_clkfreq << 1); /* Cycle, in ns */
+
+ if ( a < 2 )
+ a = 8; /* map to Cycles */
+
+ return ( (fs * a) >> 2 ); /* in 4 ns units */
}
int
-sbicfromscsiperiod(dev, regs, p)
- struct sbic_softc *dev;
- sbic_regmap_p regs;
- int p;
+sbicfromscsiperiod(dev, p)
+ struct sbic_softc *dev;
+ int p;
{
- register unsigned int fs, ret;
+ unsigned fs,
+ ret;
+
+ /*
+ * Just the inverse of the above
+ */
+ GET_SBIC_myid(dev->sc_sbicp, fs);
+
+ fs = (fs >> 6) + 2; /* DIV */
+
+ fs = (fs * 10000) / (dev->sc_clkfreq << 1); /* Cycle, in ns */
- /* Just the inverse of the above */
+ ret = p << 2; /* in ns units */
+ ret = ret / fs; /* in Cycles */
- GET_SBIC_myid(regs,fs);
- fs = (fs >>6) + 2; /* DIV */
- fs = (fs * 10000) / (dev->sc_clkfreq<<1); /* Cycle, in ns */
+ if ( ret < sbic_min_period )
+ return(sbic_min_period);
- ret = p << 2; /* in ns units */
- ret = ret / fs; /* in Cycles */
- if (ret < sbic_min_period)
- return(sbic_min_period);
+ /*
+ * verify rounding
+ */
+ if ( sbictoscsiperiod(dev, ret) < p )
+ ret++;
- /* verify rounding */
- if (sbictoscsiperiod(dev, regs, ret) < p)
- ret++;
- return (ret >= 8) ? 0 : ret;
+ return( (ret >= 8) ? 0 : ret );
}
#ifdef DEBUG
-
-void sbicdumpstate()
+void
+sbictimeout(dev)
+ struct sbic_softc *dev;
{
- u_char csr, asr;
+ int s,
+ asr;
- GET_SBIC_asr(debug_sbic_regs,asr);
- GET_SBIC_csr(debug_sbic_regs,csr);
- printf("%s: asr:csr(%02x:%02x)->(%02x:%02x)\n",
- (routine==1)?"sbicgo":
- (routine==2)?"sbicintr":
- (routine==3)?"sbicicmd":
- (routine==4)?"sbicnext":"unknown",
- debug_asr, debug_csr, asr, csr);
+ s = splbio();
-}
+ if ( dev->sc_dmatimo ) {
-void sbictimeout(dev)
- struct sbic_softc *dev;
-{
- int s, asr;
-
- /* Dump this every second while there's an active command */
- if( dev->sc_nexus ) {
- s = splbio();
- GET_SBIC_asr(dev->sc_sbicp, asr);
- if( asr & SBIC_ASR_INT ) {
- /* We need to service a missed IRQ */
- printf("Servicing a missed int:(%02x,%02x)->(%02x,??)\n",
- debug_asr, debug_csr, asr);
- sbicintr(dev);
- }
- splx(s);
- sbicdumpstate();
- timeout((void *)sbictimeout, (void*)dev, sbic_timeout * hz);
- } else timeout_active = 0;
-}
+ if ( dev->sc_dmatimo > 1 ) {
+
+ printf("%s: dma timeout #%d\n", dev->sc_dev.dv_xname,
+ dev->sc_dmatimo - 1);
+ GET_SBIC_asr(dev->sc_sbicp, asr);
+
+ if ( asr & SBIC_ASR_INT ) {
+ /*
+ * We need to service a missed IRQ
+ */
+ sbicintr(dev);
+ }
+ }
+
+ dev->sc_dmatimo++;
+ }
+
+ splx(s);
+
+ timeout((void *)sbictimeout, dev, 30 * hz);
+}
#endif
diff --git a/sys/arch/mvme68k/dev/sbicreg.h b/sys/arch/mvme68k/dev/sbicreg.h
index 1d645cfbaa4..ad3c3d18ed2 100644
--- a/sys/arch/mvme68k/dev/sbicreg.h
+++ b/sys/arch/mvme68k/dev/sbicreg.h
@@ -1,4 +1,4 @@
-/* $Id: sbicreg.h,v 1.2 1995/11/07 08:49:27 deraadt Exp $ */
+/* $OpenBSD: sbicreg.h,v 1.3 1996/04/28 11:24:46 deraadt Exp $ */
/*
* Copyright (c) 1990 The Regents of the University of California.
@@ -17,8 +17,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -35,110 +35,110 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)scsireg.h 7.3 (Berkeley) 2/5/91
+ * @(#)scsireg.h 7.3 (Berkeley) 2/5/91
*/
/*
- * AMD AM33C93A SCSI interface hardware description.
+ * WD33C93 SCSI interface hardware description.
*
* Using parts of the Mach scsi driver for the 33C93
*/
-#define SBIC_myid 0
-#define SBIC_cdbsize 0
-#define SBIC_control 1
-#define SBIC_timeo 2
-#define SBIC_cdb1 3
-#define SBIC_tsecs 3
-#define SBIC_cdb2 4
-#define SBIC_theads 4
-#define SBIC_cdb3 5
-#define SBIC_tcyl_hi 5
-#define SBIC_cdb4 6
-#define SBIC_tcyl_lo 6
-#define SBIC_cdb5 7
-#define SBIC_addr_hi 7
-#define SBIC_cdb6 8
-#define SBIC_addr_2 8
-#define SBIC_cdb7 9
-#define SBIC_addr_3 9
-#define SBIC_cdb8 10
-#define SBIC_addr_lo 10
-#define SBIC_cdb9 11
-#define SBIC_secno 11
-#define SBIC_cdb10 12
-#define SBIC_headno 12
-#define SBIC_cdb11 13
-#define SBIC_cylno_hi 13
-#define SBIC_cdb12 14
-#define SBIC_cylno_lo 14
-#define SBIC_tlun 15
-#define SBIC_cmd_phase 16
-#define SBIC_syn 17
-#define SBIC_count_hi 18
-#define SBIC_count_med 19
-#define SBIC_count_lo 20
-#define SBIC_selid 21
-#define SBIC_rselid 22
-#define SBIC_csr 23
-#define SBIC_cmd 24
-#define SBIC_data 25
+#define SBIC_myid 0
+#define SBIC_cdbsize 0
+#define SBIC_control 1
+#define SBIC_timeo 2
+#define SBIC_cdb1 3
+#define SBIC_tsecs 3
+#define SBIC_cdb2 4
+#define SBIC_theads 4
+#define SBIC_cdb3 5
+#define SBIC_tcyl_hi 5
+#define SBIC_cdb4 6
+#define SBIC_tcyl_lo 6
+#define SBIC_cdb5 7
+#define SBIC_addr_hi 7
+#define SBIC_cdb6 8
+#define SBIC_addr_2 8
+#define SBIC_cdb7 9
+#define SBIC_addr_3 9
+#define SBIC_cdb8 10
+#define SBIC_addr_lo 10
+#define SBIC_cdb9 11
+#define SBIC_secno 11
+#define SBIC_cdb10 12
+#define SBIC_headno 12
+#define SBIC_cdb11 13
+#define SBIC_cylno_hi 13
+#define SBIC_cdb12 14
+#define SBIC_cylno_lo 14
+#define SBIC_tlun 15
+#define SBIC_cmd_phase 16
+#define SBIC_syn 17
+#define SBIC_count_hi 18
+#define SBIC_count_med 19
+#define SBIC_count_lo 20
+#define SBIC_selid 21
+#define SBIC_rselid 22
+#define SBIC_csr 23
+#define SBIC_cmd 24
+#define SBIC_data 25
/* sbic_asr is addressed directly */
/*
- * Register defines
+ * Register defines
*/
/*
* Auxiliary Status Register
*/
-#define SBIC_ASR_INT 0x80 /* Interrupt pending */
-#define SBIC_ASR_LCI 0x40 /* Last command ignored */
-#define SBIC_ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */
-#define SBIC_ASR_CIP 0x10 /* Busy, cmd unavail also */
-#define SBIC_ASR_xxx 0x0c
-#define SBIC_ASR_PE 0x02 /* Parity error (even) */
-#define SBIC_ASR_DBR 0x01 /* Data Buffer Ready */
+#define SBIC_ASR_INT 0x80 /* Interrupt pending */
+#define SBIC_ASR_LCI 0x40 /* Last command ignored */
+#define SBIC_ASR_BSY 0x20 /* Busy, only cmd/data/asr readable */
+#define SBIC_ASR_CIP 0x10 /* Busy, cmd unavail also */
+#define SBIC_ASR_xxx 0x0c
+#define SBIC_ASR_PE 0x02 /* Parity error (even) */
+#define SBIC_ASR_DBR 0x01 /* Data Buffer Ready */
/*
* My ID register, and/or CDB Size
*/
-#define SBIC_ID_FS_8_10 0x00 /* Input clock is 8-10 Mhz */
- /* 11 Mhz is invalid */
-#define SBIC_ID_FS_12_15 0x40 /* Input clock is 12-15 Mhz */
-#define SBIC_ID_FS_16_20 0x80 /* Input clock is 16-20 Mhz */
-#define SBIC_ID_EHP 0x10 /* Enable host parity */
-#define SBIC_ID_EAF 0x08 /* Enable Advanced Features */
-#define SBIC_ID_MASK 0x07
-#define SBIC_ID_CBDSIZE_MASK 0x0f /* if unk SCSI cmd group */
+#define SBIC_ID_FS_8_10 0x00 /* Input clock is 8-10 Mhz */
+ /* 11 Mhz is invalid */
+#define SBIC_ID_FS_12_15 0x40 /* Input clock is 12-15 Mhz */
+#define SBIC_ID_FS_16_20 0x80 /* Input clock is 16-20 Mhz */
+#define SBIC_ID_EHP 0x10 /* Enable host parity */
+#define SBIC_ID_EAF 0x08 /* Enable Advanced Features */
+#define SBIC_ID_MASK 0x07
+#define SBIC_ID_CBDSIZE_MASK 0x0f /* if unk SCSI cmd group */
/*
* Control register
*/
-#define SBIC_CTL_DMA 0x80 /* Single byte dma */
-#define SBIC_CTL_DBA_DMA 0x40 /* direct buffer acces (bus master)*/
-#define SBIC_CTL_BURST_DMA 0x20 /* continuous mode (8237) */
-#define SBIC_CTL_NO_DMA 0x00 /* Programmed I/O */
-#define SBIC_CTL_HHP 0x10 /* Halt on host parity error */
-#define SBIC_CTL_EDI 0x08 /* Ending disconnect interrupt */
-#define SBIC_CTL_IDI 0x04 /* Intermediate disconnect interrupt*/
-#define SBIC_CTL_HA 0x02 /* Halt on ATN */
-#define SBIC_CTL_HSP 0x01 /* Halt on SCSI parity error */
+#define SBIC_CTL_DMA 0x80 /* Single byte dma */
+#define SBIC_CTL_DBA_DMA 0x40 /* direct buffer acces (bus master)*/
+#define SBIC_CTL_BURST_DMA 0x20 /* continuous mode (8237) */
+#define SBIC_CTL_NO_DMA 0x00 /* Programmed I/O */
+#define SBIC_CTL_HHP 0x10 /* Halt on host parity error */
+#define SBIC_CTL_EDI 0x08 /* Ending disconnect interrupt */
+#define SBIC_CTL_IDI 0x04 /* Intermediate disconnect interrupt*/
+#define SBIC_CTL_HA 0x02 /* Halt on ATN */
+#define SBIC_CTL_HSP 0x01 /* Halt on SCSI parity error */
/*
* Timeout period register
* [val in msecs, input clk in 0.1 Mhz]
*/
-#define SBIC_TIMEOUT(val,clk) ((((val) * (clk)) / 800) + 1)
+#define SBIC_TIMEOUT(val,clk) ((((val) * (clk)) / 800) + 1)
/*
* CDBn registers, note that
- * cdb11 is used for status byte in target mode (send-status-and-cc)
- * cdb12 sez if linked command complete, and w/flag if so
+ * cdb11 is used for status byte in target mode (send-status-and-cc)
+ * cdb12 sez if linked command complete, and w/flag if so
*/
/*
@@ -146,39 +146,39 @@
* [holds target status when select-and-xfer]
*/
-#define SBIC_TLUN_VALID 0x80 /* did we receive an Identify msg */
-#define SBIC_TLUN_DOK 0x40 /* Disconnect OK */
-#define SBIC_TLUN_xxx 0x38
-#define SBIC_TLUN_MASK 0x07
+#define SBIC_TLUN_VALID 0x80 /* did we receive an Identify msg */
+#define SBIC_TLUN_DOK 0x40 /* Disconnect OK */
+#define SBIC_TLUN_xxx 0x38
+#define SBIC_TLUN_MASK 0x07
/*
* Command Phase register
*/
-#define SBIC_CPH_MASK 0x7f /* values/restarts are cmd specific */
-#define SBIC_CPH(p) ((p) & SBIC_CPH_MASK)
+#define SBIC_CPH_MASK 0x7f /* values/restarts are cmd specific */
+#define SBIC_CPH(p) ((p) & SBIC_CPH_MASK)
/*
* FIFO register
*/
-#define SBIC_FIFO_DEEP 12
+#define SBIC_FIFO_DEEP 12
/*
* maximum possible size in TC registers. Since this is 24 bit, it's easy
*/
-#define SBIC_TC_MAX ((1 << 24) - 1)
+#define SBIC_TC_MAX ((1 << 24) - 1)
/*
* Synchronous xfer register
*/
-#define SBIC_SYN_OFF_MASK 0x0f
-#define SBIC_SYN_MAX_OFFSET SBIC_FIFO_DEEP
-#define SBIC_SYN_PER_MASK 0x70
-#define SBIC_SYN_MIN_PERIOD 2 /* upto 8, encoded as 0 */
+#define SBIC_SYN_OFF_MASK 0x0f
+#define SBIC_SYN_MAX_OFFSET SBIC_FIFO_DEEP
+#define SBIC_SYN_PER_MASK 0x70
+#define SBIC_SYN_MIN_PERIOD 2 /* upto 8, encoded as 0 */
-#define SBIC_SYN(o,p) \
+#define SBIC_SYN(o,p) \
(((o) & SBIC_SYN_OFF_MASK) | (((p) << 4) & SBIC_SYN_PER_MASK))
/*
@@ -190,142 +190,143 @@
* Destination ID (selid) register
*/
-#define SBIC_SID_SCC 0x80 /* Select command chaining (tgt) */
-#define SBIC_SID_DPD 0x40 /* Data phase direction (inittor) */
-#define SBIC_SID_FROM_SCSI 0x40
-#define SBIC_SID_TO_SCSI 0x00
-#define SBIC_SID_xxx 0x38
-#define SBIC_SID_IDMASK 0x07
+#define SBIC_SID_SCC 0x80 /* Select command chaining (tgt) */
+#define SBIC_SID_DPD 0x40 /* Data phase direction (inittor) */
+#define SBIC_SID_FROM_SCSI 0x40
+#define SBIC_SID_TO_SCSI 0x00
+#define SBIC_SID_xxx 0x38
+#define SBIC_SID_IDMASK 0x07
/*
* Source ID (rselid) register
*/
-#define SBIC_RID_ER 0x80 /* Enable reselection */
-#define SBIC_RID_ES 0x40 /* Enable selection */
-#define SBIC_RID_DSP 0x20 /* Disable select parity */
-#define SBIC_RID_SIV 0x08 /* Source ID valid */
-#define SBIC_RID_MASK 0x07
+#define SBIC_RID_ER 0x80 /* Enable reselection */
+#define SBIC_RID_ES 0x40 /* Enable selection */
+#define SBIC_RID_DSP 0x20 /* Disable select parity */
+#define SBIC_RID_SIV 0x08 /* Source ID valid */
+#define SBIC_RID_MASK 0x07
/*
* Status register
*/
-#define SBIC_CSR_CAUSE 0xf0
-#define SBIC_CSR_RESET 0x00 /* chip was reset */
-#define SBIC_CSR_CMD_DONE 0x10 /* cmd completed */
-#define SBIC_CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/
-#define SBIC_CSR_CMD_ERR 0x40 /* end with error */
-#define SBIC_CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */
+#define SBIC_CSR_CAUSE 0xf0
+#define SBIC_CSR_RESET 0x00 /* chip was reset */
+#define SBIC_CSR_CMD_DONE 0x10 /* cmd completed */
+#define SBIC_CSR_CMD_STOPPED 0x20 /* interrupted or abrted*/
+#define SBIC_CSR_CMD_ERR 0x40 /* end with error */
+#define SBIC_CSR_BUS_SERVICE 0x80 /* REQ pending on the bus */
-#define SBIC_CSR_QUALIFIER 0x0f
+#define SBIC_CSR_QUALIFIER 0x0f
/* Reset State Interrupts */
-#define SBIC_CSR_RESET 0x00 /* reset w/advanced features*/
-#define SBIC_CSR_RESET_AM 0x01 /* reset w/advanced features*/
+#define SBIC_CSR_RESET 0x00 /* reset w/advanced features*/
+#define SBIC_CSR_RESET_AM 0x01 /* reset w/advanced features*/
/* Successful Completion Interrupts */
-#define SBIC_CSR_TARGET 0x10 /* reselect complete */
-#define SBIC_CSR_INITIATOR 0x11 /* select complete */
-#define SBIC_CSR_WO_ATN 0x13 /* tgt mode completion */
-#define SBIC_CSR_W_ATN 0x14 /* ditto */
-#define SBIC_CSR_XLATED 0x15 /* translate address cmd */
-#define SBIC_CSR_S_XFERRED 0x16 /* initiator mode completion*/
-#define SBIC_CSR_XFERRED 0x18 /* phase in low bits */
+#define SBIC_CSR_TARGET 0x10 /* reselect complete */
+#define SBIC_CSR_INITIATOR 0x11 /* select complete */
+#define SBIC_CSR_WO_ATN 0x13 /* tgt mode completion */
+#define SBIC_CSR_W_ATN 0x14 /* ditto */
+#define SBIC_CSR_XLATED 0x15 /* translate address cmd */
+#define SBIC_CSR_S_XFERRED 0x16 /* initiator mode completion*/
+#define SBIC_CSR_XFERRED 0x18 /* phase in low bits */
/* Paused or Aborted Interrupts */
-#define SBIC_CSR_MSGIN_W_ACK 0x20 /* (I) msgin, ACK asserted*/
-#define SBIC_CSR_SDP 0x21 /* (I) SDP msg received */
-#define SBIC_CSR_SEL_ABRT 0x22 /* sel/resel aborted */
-#define SBIC_CSR_XFR_PAUSED 0x23 /* (T) no ATN */
-#define SBIC_CSR_XFR_PAUSED_ATN 0x24 /* (T) ATN is asserted */
-#define SBIC_CSR_RSLT_AM 0x27 /* (I) lost selection (AM) */
-#define SBIC_CSR_MIS 0x28 /* (I) xfer aborted, ph mis */
+#define SBIC_CSR_MSGIN_W_ACK 0x20 /* (I) msgin, ACK asserted*/
+#define SBIC_CSR_SDP 0x21 /* (I) SDP msg received */
+#define SBIC_CSR_SEL_ABRT 0x22 /* sel/resel aborted */
+#define SBIC_CSR_XFR_PAUSED 0x23 /* (T) no ATN */
+#define SBIC_CSR_XFR_PAUSED_ATN 0x24 /* (T) ATN is asserted */
+#define SBIC_CSR_RSLT_AM 0x27 /* (I) lost selection (AM) */
+#define SBIC_CSR_MIS 0x28 /* (I) xfer aborted, ph mis */
/* Terminated Interrupts */
-#define SBIC_CSR_CMD_INVALID 0x40
-#define SBIC_CSR_DISC 0x41 /* (I) tgt disconnected */
-#define SBIC_CSR_SEL_TIMEO 0x42
-#define SBIC_CSR_PE 0x43 /* parity error */
-#define SBIC_CSR_PE_ATN 0x44 /* ditto, ATN is asserted */
-#define SBIC_CSR_XLATE_TOOBIG 0x45
-#define SBIC_CSR_RSLT_NOAM 0x46 /* (I) lost sel, no AM mode */
-#define SBIC_CSR_BAD_STATUS 0x47 /* status byte was nok */
-#define SBIC_CSR_MIS_1 0x48 /* ph mis, see low bits */
+#define SBIC_CSR_CMD_INVALID 0x40
+#define SBIC_CSR_DISC 0x41 /* (I) tgt disconnected */
+#define SBIC_CSR_SEL_TIMEO 0x42
+#define SBIC_CSR_PE 0x43 /* parity error */
+#define SBIC_CSR_PE_ATN 0x44 /* ditto, ATN is asserted */
+#define SBIC_CSR_XLATE_TOOBIG 0x45
+#define SBIC_CSR_RSLT_NOAM 0x46 /* (I) lost sel, no AM mode */
+#define SBIC_CSR_BAD_STATUS 0x47 /* status byte was nok */
+#define SBIC_CSR_MIS_1 0x48 /* ph mis, see low bits */
/* Service Required Interrupts */
-#define SBIC_CSR_RSLT_NI 0x80 /* reselected, no ify msg */
-#define SBIC_CSR_RSLT_IFY 0x81 /* ditto, AM mode, got ify */
-#define SBIC_CSR_SLT 0x82 /* selected, no ATN */
-#define SBIC_CSR_SLT_ATN 0x83 /* selected with ATN */
-#define SBIC_CSR_ATN 0x84 /* (T) ATN asserted */
-#define SBIC_CSR_DISC_1 0x85 /* (I) bus is free */
-#define SBIC_CSR_UNK_GROUP 0x87 /* strange CDB1 */
-#define SBIC_CSR_MIS_2 0x88 /* (I) ph mis, see low bits */
+#define SBIC_CSR_RSLT_NI 0x80 /* reselected, no ify msg */
+#define SBIC_CSR_RSLT_IFY 0x81 /* ditto, AM mode, got ify */
+#define SBIC_CSR_SLT 0x82 /* selected, no ATN */
+#define SBIC_CSR_SLT_ATN 0x83 /* selected with ATN */
+#define SBIC_CSR_ATN 0x84 /* (T) ATN asserted */
+#define SBIC_CSR_DISC_1 0x85 /* (I) bus is free */
+#define SBIC_CSR_UNK_GROUP 0x87 /* strange CDB1 */
+#define SBIC_CSR_MIS_2 0x88 /* (I) ph mis, see low bits */
-#define SBIC_PHASE(csr) SCSI_PHASE(csr)
+#define SBIC_PHASE(csr) SCSI_PHASE(csr)
/*
* Command register (command codes)
*/
-#define SBIC_CMD_SBT 0x80 /* Single byte xfer qualifier */
-#define SBIC_CMD_MASK 0x7f
-
- /* Miscellaneous */
-#define SBIC_CMD_RESET 0x00 /* (DTI) lev I */
-#define SBIC_CMD_ABORT 0x01 /* (DTI) lev I */
-#define SBIC_CMD_DISC 0x04 /* ( TI) lev I */
-#define SBIC_CMD_SSCC 0x0d /* ( TI) lev I */
-#define SBIC_CMD_SET_IDI 0x0f /* (DTI) lev I */
-#define SBIC_CMD_XLATE 0x18 /* (DT ) lev II */
-
- /* Initiator state */
-#define SBIC_CMD_SET_ATN 0x02 /* ( I) lev I */
-#define SBIC_CMD_CLR_ACK 0x03 /* ( I) lev I */
-#define SBIC_CMD_XFER_PAD 0x19 /* ( I) lev II */
-#define SBIC_CMD_XFER_INFO 0x20 /* ( I) lev II */
-
- /* Target state */
-#define SBIC_CMD_SND_DISC 0x0e /* ( T ) lev II */
-#define SBIC_CMD_RCV_CMD 0x10 /* ( T ) lev II */
-#define SBIC_CMD_RCV_DATA 0x11 /* ( T ) lev II */
-#define SBIC_CMD_RCV_MSG_OUT 0x12 /* ( T ) lev II */
-#define SBIC_CMD_RCV 0x13 /* ( T ) lev II */
-#define SBIC_CMD_SND_STATUS 0x14 /* ( T ) lev II */
-#define SBIC_CMD_SND_DATA 0x15 /* ( T ) lev II */
-#define SBIC_CMD_SND_MSG_IN 0x16 /* ( T ) lev II */
-#define SBIC_CMD_SND 0x17 /* ( T ) lev II */
-
- /* Disconnected state */
-#define SBIC_CMD_RESELECT 0x05 /* (D ) lev II */
-#define SBIC_CMD_SEL_ATN 0x06 /* (D ) lev II */
-#define SBIC_CMD_SEL 0x07 /* (D ) lev II */
-#define SBIC_CMD_SEL_ATN_XFER 0x08 /* (D I) lev II */
-#define SBIC_CMD_SEL_XFER 0x09 /* (D I) lev II */
-#define SBIC_CMD_RESELECT_RECV 0x0a /* (DT ) lev II */
-#define SBIC_CMD_RESELECT_SEND 0x0b /* (DT ) lev II */
-#define SBIC_CMD_WAIT_SEL_RECV 0x0c /* (DT ) lev II */
+#define SBIC_CMD_SBT 0x80 /* Single byte xfer qualifier */
+#define SBIC_CMD_MASK 0x7f
+
+ /* Miscellaneous */
+#define SBIC_CMD_RESET 0x00 /* (DTI) lev I */
+#define SBIC_CMD_ABORT 0x01 /* (DTI) lev I */
+#define SBIC_CMD_DISC 0x04 /* ( TI) lev I */
+#define SBIC_CMD_SSCC 0x0d /* ( TI) lev I */
+#define SBIC_CMD_SET_IDI 0x0f /* (DTI) lev I */
+#define SBIC_CMD_XLATE 0x18 /* (DT ) lev II */
+
+ /* Initiator state */
+#define SBIC_CMD_SET_ATN 0x02 /* ( I) lev I */
+#define SBIC_CMD_CLR_ACK 0x03 /* ( I) lev I */
+#define SBIC_CMD_XFER_PAD 0x19 /* ( I) lev II */
+#define SBIC_CMD_XFER_INFO 0x20 /* ( I) lev II */
+
+ /* Target state */
+#define SBIC_CMD_SND_DISC 0x0e /* ( T ) lev II */
+#define SBIC_CMD_RCV_CMD 0x10 /* ( T ) lev II */
+#define SBIC_CMD_RCV_DATA 0x11 /* ( T ) lev II */
+#define SBIC_CMD_RCV_MSG_OUT 0x12 /* ( T ) lev II */
+#define SBIC_CMD_RCV 0x13 /* ( T ) lev II */
+#define SBIC_CMD_SND_STATUS 0x14 /* ( T ) lev II */
+#define SBIC_CMD_SND_DATA 0x15 /* ( T ) lev II */
+#define SBIC_CMD_SND_MSG_IN 0x16 /* ( T ) lev II */
+#define SBIC_CMD_SND 0x17 /* ( T ) lev II */
+
+ /* Disconnected state */
+#define SBIC_CMD_RESELECT 0x05 /* (D ) lev II */
+#define SBIC_CMD_SEL_ATN 0x06 /* (D ) lev II */
+#define SBIC_CMD_SEL 0x07 /* (D ) lev II */
+#define SBIC_CMD_SEL_ATN_XFER 0x08 /* (D I) lev II */
+#define SBIC_CMD_SEL_XFER 0x09 /* (D I) lev II */
+#define SBIC_CMD_RESELECT_RECV 0x0a /* (DT ) lev II */
+#define SBIC_CMD_RESELECT_SEND 0x0b /* (DT ) lev II */
+#define SBIC_CMD_WAIT_SEL_RECV 0x0c /* (DT ) lev II */
/* approximate, but we won't do SBT on selects */
-#define sbic_isa_select(cmd) (((cmd) > 0x5) && ((cmd) < 0xa))
+#define sbic_isa_select(cmd) (((cmd) > 0x5) && ((cmd) < 0xa))
-#define PAD(n) char n;
-#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA
+#define PAD(n) char n;
+#define SBIC_MACHINE_DMA_MODE SBIC_CTL_DMA
typedef struct {
- volatile unsigned char sbic_asr; /* r : Aux Status Register */
-#define sbic_address sbic_asr /* w : desired register no */
- /* PAD(pad1); */
- volatile unsigned char sbic_value; /* rw: register value */
+ volatile unsigned char sbic_asr; /* r : Aux Status Register */
+#define sbic_address sbic_asr /* w : desired register no */
+ volatile unsigned char sbic_value; /* rw: register value */
} sbic_padded_ind_regmap_t;
typedef volatile sbic_padded_ind_regmap_t *sbic_regmap_p;
-#define sbic_read_reg(regs,regno,val) do { \
- (regs)->sbic_address = (regno); \
- (val) = (regs)->sbic_value; \
- } while (0)
+#define sbic_read_reg(regs,regno,val) \
+ do { \
+ (regs)->sbic_address = (regno); \
+ (val) = (regs)->sbic_value; \
+ } while (0)
-#define sbic_write_reg(regs,regno,val) do { \
- (regs)->sbic_address = (regno); \
- (regs)->sbic_value = (val); \
- } while (0)
+#define sbic_write_reg(regs,regno,val) \
+ do { \
+ (regs)->sbic_address = (regno); \
+ (regs)->sbic_value = (val); \
+ } while (0)
#define SET_SBIC_myid(regs,val) sbic_write_reg(regs,SBIC_myid,val)
#define GET_SBIC_myid(regs,val) sbic_read_reg(regs,SBIC_myid,val)
@@ -382,43 +383,55 @@ typedef volatile sbic_padded_ind_regmap_t *sbic_regmap_p;
#define SET_SBIC_data(regs,val) sbic_write_reg(regs,SBIC_data,val)
#define GET_SBIC_data(regs,val) sbic_read_reg(regs,SBIC_data,val)
-#define SBIC_TC_PUT(regs,val) do { \
- sbic_write_reg(regs,SBIC_count_hi,((val)>>16)); \
- (regs)->sbic_value = (val)>>8; \
- (regs)->sbic_value = (val); \
-} while (0)
-#define SBIC_TC_GET(regs,val) do { \
- sbic_read_reg(regs,SBIC_count_hi,(val)); \
- (val) = ((val)<<8) | (regs)->sbic_value; \
- (val) = ((val)<<8) | (regs)->sbic_value; \
-} while (0)
-
-#define SBIC_LOAD_COMMAND(regs,cmd,cmdsize) do { \
- int n=(cmdsize)-1; \
- char *ptr = (char*)(cmd); \
- sbic_write_reg(regs,SBIC_cdb1,*ptr++); \
- while (n-- > 0) (regs)->sbic_value = *ptr++; \
-} while (0)
+#define SBIC_TC_PUT(regs,val) \
+ do { \
+ sbic_write_reg(regs,SBIC_count_hi,((val)>>16)); \
+ (regs)->sbic_value = (val)>>8; \
+ (regs)->sbic_value = (val); \
+ } while (0)
+
+#define SBIC_TC_GET(regs,val) \
+ do { \
+ sbic_read_reg(regs,SBIC_count_hi,(val)); \
+ (val) = ((val)<<8) | (regs)->sbic_value; \
+ (val) = ((val)<<8) | (regs)->sbic_value; \
+ } while (0)
+
+#define SBIC_LOAD_COMMAND(regs,cmd,cmdsize) \
+ do { \
+ int n = (cmdsize) - 1; \
+ char *ptr = (char *)(cmd); \
+ sbic_write_reg(regs, SBIC_cdb1, *ptr++); \
+ while(n-- > 0) (regs)->sbic_value = *ptr++; \
+ } while (0)
#define GET_SBIC_asr(regs,val) (val) = (regs)->sbic_asr
-#define WAIT_CIP(regs) do { \
- while ((regs)->sbic_asr & SBIC_ASR_CIP) \
- ; \
-} while (0)
-
-/* transmit a byte in programmed I/O mode */
-#define SEND_BYTE(regs, ch) do { \
- WAIT_CIP(regs); \
- SET_SBIC_cmd(regs, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
- SBIC_WAIT(regs, SBIC_ASR_DBR, 0); \
- SET_SBIC_data(regs, ch); \
- } while (0)
-
-/* receive a byte in programmed I/O mode */
-#define RECV_BYTE(regs, ch) do { \
- WAIT_CIP(regs); \
- SET_SBIC_cmd(regs, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
- SBIC_WAIT(regs, SBIC_ASR_DBR, 0); \
- GET_SBIC_data(regs, ch); \
- } while (0)
+#define WAIT_CIP(regs) \
+ do { \
+ while ((regs)->sbic_asr & SBIC_ASR_CIP) \
+ ; \
+ } while (0)
+
+/*
+ * transmit a byte in programmed I/O mode
+ **/
+#define SEND_BYTE(regs, ch) \
+ do { \
+ WAIT_CIP(regs); \
+ SET_SBIC_cmd(regs, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
+ SBIC_WAIT(regs, SBIC_ASR_DBR, 0); \
+ SET_SBIC_data(regs, ch); \
+ } while (0)
+
+/*
+ * receive a byte in programmed I/O mode
+ */
+#define RECV_BYTE(regs, ch) \
+ do { \
+ WAIT_CIP(regs); \
+ SET_SBIC_cmd(regs, SBIC_CMD_SBT | SBIC_CMD_XFER_INFO); \
+ SBIC_WAIT(regs, SBIC_ASR_DBR, 0); \
+ GET_SBIC_data(regs, ch); \
+ } while (0)
+
diff --git a/sys/arch/mvme68k/dev/sbicvar.h b/sys/arch/mvme68k/dev/sbicvar.h
index c198db322a3..bbf96599e6c 100644
--- a/sys/arch/mvme68k/dev/sbicvar.h
+++ b/sys/arch/mvme68k/dev/sbicvar.h
@@ -1,4 +1,4 @@
-/* $Id: sbicvar.h,v 1.2 1995/11/07 08:49:28 deraadt Exp $ */
+/* $OpenBSD: sbicvar.h,v 1.3 1996/04/28 11:24:47 deraadt Exp $ */
/*
* Copyright (c) 1990 The Regents of the University of California.
@@ -17,8 +17,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
@@ -35,23 +35,19 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)scsivar.h 7.1 (Berkeley) 5/8/90
+ * @(#)scsivar.h 7.1 (Berkeley) 5/8/90
*/
#ifndef _SBICVAR_H_
#define _SBICVAR_H_
#include <sys/malloc.h>
+
/*
- * The largest single request will be MAXPHYS bytes which will require
- * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
- * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
- * buffer is not page aligned (+1).
+ * DMA chains are used for Scatter-Gather DMA.
*/
-#define DMAMAXIO (MAXPHYS/NBPG+1)
-
-struct dma_chain {
- int dc_count;
- char *dc_addr;
+struct dma_chain {
+ int dc_count;
+ char *dc_addr;
};
/*
@@ -63,25 +59,23 @@ struct dma_chain {
* occasionally xs->retries.
*/
struct sbic_acb {
- TAILQ_ENTRY(sbic_acb) chain;
- struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
- int flags; /* Status */
-#define ACB_FREE 0x00
-#define ACB_ACTIVE 0x01
-#define ACB_DONE 0x04
-#define ACB_CHKSENSE 0x08
-#define ACB_BBUF 0x10 /* DMA input needs to be copied from bounce */
-#define ACB_DATAIN 0x20 /* DMA direction flag */
- struct scsi_generic cmd; /* SCSI command block */
- int clen;
- struct dma_chain sc_kv; /* Virtual address of whole DMA */
- struct dma_chain sc_pa; /* Physical address of DMA segment */
- u_long sc_tcnt; /* number of bytes for this DMA */
- u_char *sc_dmausrbuf; /* user buffer kva - for bounce copy */
- u_long sc_dmausrlen; /* length of bounce copy */
- u_short sc_dmacmd; /* Internal data for this DMA */
- char *pa_addr; /* XXXX initial phys addr */
- u_char *sc_usrbufpa; /* user buffer phys addr */
+ TAILQ_ENTRY(sbic_acb) chain;
+ struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
+ int flags; /* Status */
+#define ACB_FREE 0x00
+#define ACB_ACTIVE 0x01
+#define ACB_DONE 0x04
+#define ACB_CHKSENSE 0x08
+#define ACB_BBUF 0x10 /* DMA input needs to be copied from bounce */
+#define ACB_DATAIN 0x20 /* DMA direction flag */
+
+ struct scsi_generic cmd; /* SCSI command block */
+ int clen;
+ struct dma_chain sc_kv; /* Virtual address of whole DMA */
+ struct dma_chain sc_pa; /* Physical address of DMA segment */
+ u_long sc_tcnt; /* number of bytes for this DMA */
+ u_short sc_dmacmd; /* Internal data for this DMA */
+ char *pa_addr; /* XXXX initial phys addr */
};
/*
@@ -90,136 +84,119 @@ struct sbic_acb {
* this for now. Is there a way to reliably hook it up to sc->fordriver??
*/
struct sbic_tinfo {
- int cmds; /* #commands processed */
- int dconns; /* #disconnects */
- int touts; /* #timeouts */
- int perrs; /* #parity errors */
- int senses; /* #request sense commands sent */
- u_char* bounce; /* Bounce buffer for this device */
- ushort lubusy; /* What local units/subr. are busy? */
- u_char flags;
- u_char period; /* Period suggestion */
- u_char offset; /* Offset suggestion */
+ int cmds; /* #commands processed */
+ int dconns; /* #disconnects */
+ int senses; /* #request sense commands sent */
+ int lubusy; /* What local units/subr. are busy? */
} tinfo_t;
-struct sbic_softc {
- struct device sc_dev;
- struct intrhand sc_ih, sc_dmaih;
- struct evcnt sc_intrcnt, sc_dmaintrcnt;
- struct target_sync {
- u_char state;
- u_char period;
- u_char offset;
- } sc_sync[8];
- u_char target; /* Currently active target */
- u_char lun;
- struct scsi_link sc_link; /* proto for sub devices */
- sbic_regmap_p sc_sbicp; /* the SBIC */
- volatile void *sc_cregs; /* driver specific regs */
-
- /* Lists of command blocks */
- TAILQ_HEAD(acb_list, sbic_acb) free_list,
- ready_list,
- nexus_list;
-
- struct sbic_acb *sc_nexus; /* current command */
- struct sbic_acb sc_acb[8]; /* the real command blocks */
- struct sbic_tinfo sc_tinfo[8];
-
- struct scsi_xfer *sc_xs; /* transfer from high level code */
- u_char sc_flags;
- u_char sc_scsiaddr;
- u_char sc_stat[2];
- u_char sc_msg[7];
- u_long sc_clkfreq;
- u_long sc_tcnt; /* number of bytes transfered */
- u_short sc_dmacmd; /* used by dma drivers */
- u_short sc_dmatimo; /* dma timeout */
- u_long sc_dmamask; /* dma valid mem mask */
- struct dma_chain *sc_cur;
- struct dma_chain *sc_last;
- int (*sc_dmago) __P((struct sbic_softc *, char *, int, int));
- int (*sc_dmanext) __P((struct sbic_softc *));
- void (*sc_dmafree) __P((struct sbic_softc *));
- void (*sc_dmastop) __P((struct sbic_softc *));
- u_short gtsc_bankmask; /* GVP specific bank selected */
-};
-
-/* sc_flags */
-#define SBICF_ALIVE 0x01 /* controller initialized */
-#define SBICF_DCFLUSH 0x02 /* need flush for overlap after dma finishes */
-#define SBICF_SELECTED 0x04 /* bus is in selected state. */
-#define SBICF_ICMD 0x08 /* Immediate command in execution */
-#define SBICF_BADDMA 0x10 /* controller can only DMA to ztwobus space */
-#define SBICF_INTR 0x40 /* SBICF interrupt expected */
-#define SBICF_INDMA 0x80 /* not used yet, DMA I/O in progress */
-
-/* sync states */
-#define SYNC_START 0 /* no sync handshake started */
-#define SYNC_SENT 1 /* we sent sync request, no answer yet */
-#define SYNC_DONE 2 /* target accepted our (or inferior) settings,
- or it rejected the request and we stay async */
+struct sbic_softc {
+ struct device sc_dev;
+ struct intrhand sc_dmaih;
+ struct intrhand sc_sbicih;
+ struct target_sync {
+ u_char state;
+ u_char period;
+ u_char offset;
+ } sc_sync[8];
+ u_char target; /* Currently active target */
+ u_char lun;
+ struct scsi_link sc_link; /* proto for sub devices */
+ sbic_regmap_p sc_sbicp; /* the SBIC */
+ void *sc_cregs; /* driver specific regs */
+ int sc_ipl;
+
+ /* Lists of command blocks */
+ TAILQ_HEAD(acb_list, sbic_acb) free_list,
+ ready_list,
+ nexus_list;
+
+ struct sbic_acb *sc_nexus; /* current command */
+ struct sbic_acb sc_acb[8]; /* the real command blocks */
+ struct sbic_tinfo sc_tinfo[8];
+
+ struct scsi_xfer *sc_xs; /* transfer from high level code */
+ u_char sc_flags;
+ u_char sc_stat[2];
+ u_char sc_msg[7];
+ u_long sc_clkfreq;
+ u_long sc_tcnt; /* number of bytes transfered */
+ u_short sc_dmacmd; /* used by dma drivers */
+ u_long sc_dmamask; /* dma valid mem mask */
#ifdef DEBUG
-#define DDB_FOLLOW 0x04
-#define DDB_IO 0x08
+ u_short sc_dmatimo; /* dma timeout */
#endif
-extern int sbic_inhibit_sync;
-extern int sbic_no_dma;
-extern int sbic_clock_override;
-
-#define PHASE 0x07 /* mask for psns/pctl phase */
-#define DATA_OUT_PHASE 0x00
-#define DATA_IN_PHASE 0x01
-#define CMD_PHASE 0x02
-#define STATUS_PHASE 0x03
-#define BUS_FREE_PHASE 0x04
-#define ARB_SEL_PHASE 0x05 /* Fuji chip combines arbitration with sel. */
-#define MESG_OUT_PHASE 0x06
-#define MESG_IN_PHASE 0x07
-
-#define MSG_CMD_COMPLETE 0x00
-#define MSG_EXT_MESSAGE 0x01
-#define MSG_SAVE_DATA_PTR 0x02
-#define MSG_RESTORE_PTR 0x03
-#define MSG_DISCONNECT 0x04
-#define MSG_INIT_DETECT_ERROR 0x05
-#define MSG_ABORT 0x06
-#define MSG_REJECT 0x07
-#define MSG_NOOP 0x08
-#define MSG_PARITY_ERROR 0x09
-#define MSG_BUS_DEVICE_RESET 0x0C
-#define MSG_IDENTIFY 0x80
-#define MSG_IDENTIFY_DR 0xc0 /* (disconnect/reconnect allowed) */
-#define MSG_SYNC_REQ 0x01
-
-#define MSG_ISIDENTIFY(x) (x&MSG_IDENTIFY)
-#define IFY_TRN 0x20
-#define IFY_LUNTRN(x) (x&0x07)
-#define IFY_LUN(x) (!(x&0x20))
-
-/* Check if high bit set */
-
-#define STS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */
-#define STS_CONDMET 0x04 /* Condition Met (ie., search worked) */
-#define STS_BUSY 0x08
-#define STS_INTERMED 0x10 /* Intermediate status sent */
-#define STS_EXT 0x80 /* Extended status valid */
-
-
-/* States returned by our state machine */
-
-#define SBIC_STATE_ERROR -1
-#define SBIC_STATE_DONE 0
-#define SBIC_STATE_RUNNING 1
-#define SBIC_STATE_DISCONNECT 2
+ struct dma_chain *sc_cur;
+ struct dma_chain *sc_last;
+ int (*sc_dmago) __P((struct sbic_softc *, char *, int, int));
+ int (*sc_dmanext) __P((struct sbic_softc *));
+ void (*sc_enintr) __P((struct sbic_softc *));
+ void (*sc_dmastop) __P((struct sbic_softc *));
+};
/*
- * XXXX
+ * sc_flags
*/
-struct scsi_fmt_cdb {
- int len; /* cdb length (in bytes) */
- u_char cdb[28]; /* cdb to use on next read/write */
-};
+#define SBICF_ALIVE 0x01 /* controller initialized */
+#define SBICF_DCFLUSH 0x02 /* need flush for overlap after dma finishes */
+#define SBICF_SELECTED 0x04 /* bus is in selected state. */
+#define SBICF_ICMD 0x08 /* Immediate command in execution */
+#define SBICF_BADDMA 0x10 /* controller can only DMA to ztwobus space */
+#define SBICF_INTR 0x40 /* SBICF interrupt expected */
+#define SBICF_INDMA 0x80 /* not used yet, DMA I/O in progress */
+
+/*
+ * sync states
+ */
+#define SYNC_START 0 /* no sync handshake started */
+#define SYNC_SENT 1 /* we sent sync request, no answer yet */
+#define SYNC_DONE 2 /* target accepted our (or inferior) settings,
+ or it rejected the request and we stay async */
+
+#define PHASE 0x07 /* mask for psns/pctl phase */
+#define DATA_OUT_PHASE 0x00
+#define DATA_IN_PHASE 0x01
+#define CMD_PHASE 0x02
+#define STATUS_PHASE 0x03
+#define BUS_FREE_PHASE 0x04
+#define ARB_SEL_PHASE 0x05 /* Fuji chip combines arbitration with sel. */
+#define MESG_OUT_PHASE 0x06
+#define MESG_IN_PHASE 0x07
+
+#define MSG_CMD_COMPLETE 0x00
+#define MSG_EXT_MESSAGE 0x01
+#define MSG_SAVE_DATA_PTR 0x02
+#define MSG_RESTORE_PTR 0x03
+#define MSG_DISCONNECT 0x04
+#define MSG_INIT_DETECT_ERROR 0x05
+#define MSG_ABORT 0x06
+#define MSG_REJECT 0x07
+#define MSG_NOOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define MSG_BUS_DEVICE_RESET 0x0C
+#define MSG_IDENTIFY 0x80
+#define MSG_IDENTIFY_DR 0xc0 /* (disconnect/reconnect allowed) */
+#define MSG_SYNC_REQ 0x01
+
+#define MSG_ISIDENTIFY(x) ((x) & MSG_IDENTIFY)
+
+
+#define STS_CHECKCOND 0x02 /* Check Condition (ie., read sense) */
+#define STS_CONDMET 0x04 /* Condition Met (ie., search worked) */
+#define STS_BUSY 0x08
+#define STS_INTERMED 0x10 /* Intermediate status sent */
+#define STS_EXT 0x80 /* Extended status valid */
+
+
+/*
+ * States returned by our state machine
+ */
+
+#define SBIC_STATE_ERROR -1
+#define SBIC_STATE_DONE 0
+#define SBIC_STATE_RUNNING 1
+#define SBIC_STATE_DISCONNECT 2
+
struct buf;
struct scsi_xfer;
diff --git a/sys/arch/mvme68k/dev/wdsc.c b/sys/arch/mvme68k/dev/wdsc.c
new file mode 100644
index 00000000000..c8e1bd7cc0c
--- /dev/null
+++ b/sys/arch/mvme68k/dev/wdsc.c
@@ -0,0 +1,349 @@
+/* $OpenBSD: wdsc.c,v 1.1 1996/04/28 11:24:48 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1996 Steve Woodford
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wdsc.c
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <mvme68k/dev/dmavar.h>
+#include <mvme68k/dev/sbicreg.h>
+#include <mvme68k/dev/sbicvar.h>
+#include <mvme68k/dev/wdscreg.h>
+#include <machine/autoconf.h>
+#include <mvme68k/dev/pccreg.h>
+
+int wdscprint __P((void *auxp, char *));
+void wdscattach __P((struct device *, struct device *, void *));
+int wdscmatch __P((struct device *, struct cfdata *, void *));
+
+void wdsc_enintr __P((struct sbic_softc *));
+int wdsc_dmago __P((struct sbic_softc *, char *, int, int));
+int wdsc_dmanext __P((struct sbic_softc *));
+void wdsc_dmastop __P((struct sbic_softc *));
+int wdsc_dmaintr __P((struct sbic_softc *));
+int wdsc_scsiintr __P((struct sbic_softc *));
+
+struct scsi_adapter wdsc_scsiswitch = {
+ sbic_scsicmd,
+ sbic_minphys,
+ 0, /* no lun support */
+ 0, /* no lun support */
+};
+
+struct scsi_device wdsc_scsidev = {
+ NULL, /* use default error handler */
+ NULL, /* do not have a start functio */
+ NULL, /* have no async handler */
+ NULL, /* Use default done routine */
+};
+
+struct cfattach wdsc_ca = {
+ sizeof(struct sbic_softc), (cfmatch_t)wdscmatch, wdscattach
+};
+
+struct cfdriver wdsc_cd = {
+ NULL, "wdsc", DV_DULL, NULL, 0
+};
+
+/*
+ * Define 'scsi_nosync = 0x00' to enable sync SCSI mode.
+ * This is untested as yet, use at your own risk...
+ */
+u_long scsi_nosync = 0xff;
+int shift_nosync = 0;
+
+/*
+ * Match for SCSI devices on the onboard WD33C93 chip
+ */
+int
+wdscmatch(pdp, cdp, auxp)
+ struct device *pdp;
+ struct cfdata *cdp;
+ void *auxp;
+{
+ /*
+ * Match everything
+ */
+ return(1);
+}
+
+
+/*
+ * Attach the wdsc driver
+ */
+void
+wdscattach(pdp, dp, auxp)
+ struct device *pdp, *dp;
+ void *auxp;
+{
+ struct sbic_softc *sc = (struct sbic_softc *)dp;
+ struct confargs *ca = auxp;
+ struct pccreg *pcc = (struct pccreg *)ca->ca_master;
+ int ipl;
+
+ sc->sc_enintr = wdsc_enintr;
+ sc->sc_dmago = wdsc_dmago;
+ sc->sc_dmanext = wdsc_dmanext;
+ sc->sc_dmastop = wdsc_dmastop;
+ sc->sc_dmacmd = 0;
+
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = 7;
+ sc->sc_link.adapter = &wdsc_scsiswitch;
+ sc->sc_link.device = &wdsc_scsidev;
+ sc->sc_link.openings = 2;
+
+ printf(": target %d\n", sc->sc_link.adapter_target);
+
+ sc->sc_cregs = (void *)pcc;
+ sc->sc_sbicp = (sbic_regmap_p)ca->ca_vaddr;
+
+ /*
+ * Eveything is a valid dma address.
+ *
+ */
+ sc->sc_dmamask = 0;
+
+ /*
+ * The onboard WD33C93 of the '147 is usually clocked at 10MHz...
+ * (We use 10 times this for accuracy in later calculations)
+ */
+ sc->sc_clkfreq = 100;
+
+ /*
+ * Initialise the hardware
+ */
+ sbicinit(sc);
+
+ /*
+ * Fix up the interrupts
+ */
+ sc->sc_dmaih.ih_fn = wdsc_dmaintr;
+ sc->sc_dmaih.ih_arg = sc;
+ sc->sc_dmaih.ih_ipl = ca->ca_ipl;
+ pcctwointr_establish(PCCV_DMA, &sc->sc_dmaih);
+
+ sc->sc_sbicih.ih_fn = wdsc_scsiintr;
+ sc->sc_sbicih.ih_arg = sc;
+ sc->sc_sbicih.ih_ipl = ca->ca_ipl;
+ pcctwointr_establish(PCCV_SBIC, &sc->sc_dmaih);
+
+ pcc->pcc_sbicirq = ca->ca_ipl | PCC_IRQ_IEN;
+ pcc->pcc_dmairq = ca->ca_ipl | PCC_IRQ_IEN;
+ pcc->pcc_dmacsr = 0;
+
+ pcc->pcc_sbicirq = ca->ca_ipl | PCC_IRQ_IEN /* | PCC_IRQ_INT */;
+
+ /*
+ * Attach all scsi units on us
+ */
+ config_found(dp, &sc->sc_link, wdscprint);
+}
+
+/*
+ * print diag if pnp is NULL else just extra
+ */
+int
+wdscprint(auxp, pnp)
+ void *auxp;
+ char *pnp;
+{
+ if (pnp == NULL)
+ return(UNCONF);
+ return(QUIET);
+}
+
+
+/*
+ * Enable DMA interrupts
+ */
+void
+wdsc_enintr(dev)
+ struct sbic_softc *dev;
+{
+ struct pccreg *pcc = dev->sc_cregs;
+
+ dev->sc_flags |= SBICF_INTR;
+
+ pcc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_IEN /*| PCC_IRQ_INT*/;
+}
+
+/*
+ * Prime the hardware for a DMA transfer
+ */
+int
+wdsc_dmago(dev, addr, count, flags)
+ struct sbic_softc *dev;
+ char *addr;
+ int count, flags;
+{
+ volatile struct pccreg *pc = dev->sc_cregs;
+
+ /*
+ * Set up the command word based on flags
+ */
+ if ( (flags & DMAGO_READ) == 0 )
+ dev->sc_dmacmd = DMAC_CSR_ENABLE | DMAC_CSR_WRITE;
+ else
+ dev->sc_dmacmd = DMAC_CSR_ENABLE;
+
+ dev->sc_flags |= SBICF_INTR;
+ dev->sc_tcnt = dev->sc_cur->dc_count << 1;
+
+ /*
+ * Prime the hardware.
+ * Note, it's probably not necessary to do this here, since dmanext
+ * is called just prior to the actual transfer.
+ */
+ pc->pcc_dmacsr = 0;
+ pc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
+ pc->pcc_dmadaddr = (unsigned long)dev->sc_cur->dc_addr;
+ pc->pcc_dmabcnt = (unsigned long)dev->sc_tcnt | (1 << 24);
+ pc->pcc_dmacsr = dev->sc_dmacmd;
+
+ return(dev->sc_tcnt);
+}
+
+/*
+ * Prime the hardware for the next DMA transfer
+ */
+int
+wdsc_dmanext(dev)
+ struct sbic_softc *dev;
+{
+ volatile struct pccreg *pc = dev->sc_cregs;
+
+ if ( dev->sc_cur > dev->sc_last ) {
+ /*
+ * Shouldn't happen !!
+ */
+ printf("wdsc_dmanext at end !!!\n");
+ wdsc_dmastop(dev);
+ return(0);
+ }
+
+ dev->sc_tcnt = dev->sc_cur->dc_count << 1;
+
+ /*
+ * Load the next DMA address
+ */
+ pc->pcc_dmacsr = 0;
+ pc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
+ pc->pcc_dmadaddr = (unsigned long)dev->sc_cur->dc_addr;
+ pc->pcc_dmabcnt = (unsigned long)dev->sc_tcnt | (1 << 24);
+ pc->pcc_dmacsr = dev->sc_dmacmd;
+
+ return(dev->sc_tcnt);
+}
+
+/*
+ * Stop DMA, and disable interrupts
+ */
+void
+wdsc_dmastop(dev)
+ struct sbic_softc *dev;
+{
+ volatile struct pccreg *pc = dev->sc_cregs;
+ int s;
+
+ s = splbio();
+
+ pc->pcc_dmacsr = 0;
+ pc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_INT;
+
+ splx(s);
+}
+
+/*
+ * Come here following a DMA interrupt
+ */
+int
+wdsc_dmaintr(dev)
+ struct sbic_softc *dev;
+{
+ volatile struct pccreg *pc = dev->sc_cregs;
+ int found = 0;
+
+ /*
+ * Really a DMA interrupt?
+ */
+ if ( (pc->pcc_dmairq & 0x80) == 0 )
+ return(0);
+
+ /*
+ * Was it a completion interrupt?
+ * XXXSCW Note: Support for other DMA interrupts is required, eg. buserr
+ */
+ if ( pc->pcc_dmacsr & DMAC_CSR_DONE ) {
+ ++found;
+
+ pc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
+ }
+
+ return(found);
+}
+
+/*
+ * Come here for SCSI interrupts
+ */
+int
+wdsc_scsiintr(dev)
+ struct sbic_softc *dev;
+{
+ volatile struct pccreg *pc = dev->sc_cregs;
+ int found;
+
+ /*
+ * Really a SCSI interrupt?
+ */
+ if ( (pc->pcc_sbicirq & 0x80) == 0 )
+ return(0);
+
+ /*
+ * Go handle it
+ */
+ found = sbicintr(dev);
+
+ /*
+ * Acknowledge and clear the interrupt
+ */
+ pc->pcc_sbicirq = dev->sc_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
+
+ return(found);
+}
diff --git a/sys/arch/mvme68k/dev/wdscreg.h b/sys/arch/mvme68k/dev/wdscreg.h
new file mode 100644
index 00000000000..e439e627751
--- /dev/null
+++ b/sys/arch/mvme68k/dev/wdscreg.h
@@ -0,0 +1,53 @@
+/* $OpenBSD: wdscreg.h,v 1.1 1996/04/28 11:24:49 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1994 Christian E. Hopps
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dmareg.h
+ */
+#ifndef _MVME68K_DEV_WDSCREG_H_
+#define _MVME68K_DEV_WDSCREG_H_
+
+#define DMAC_CSR_ENABLE (1 << 0) /* Enable the DMAC */
+#define DMAC_CSR_TABLE (1 << 1) /* Select Table Mode */
+#define DMAC_CSR_WRITE (1 << 2) /* Write data from RAM to SCSI */
+#define DMAC_CSR_TBUSERR (1 << 3) /* Bus error during table walk */
+#define DMAC_CSR_DBUSERR (1 << 4) /* Bus error during data xfer */
+#define DMAC_CSR_TSIZE (1 << 5) /* Table addr. not in 32 bits */
+#define DMAC_CSR_8BITS (1 << 6) /* Non-8 bit handshake */
+#define DMAC_CSR_DONE (1 << 7) /* Transfer complete, or error */
+
+#define DMAC_SR_HOLDING 0x0f /* Data holding state */
+#define DMAC_SR_INCREMENT 0xf0 /* Increment value */
+
+#endif