diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-04-28 11:24:50 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-04-28 11:24:50 +0000 |
commit | 04e89f5b87e945cfe47ccf26d7763132c96772fd (patch) | |
tree | 0ed05bc667dbf2012b55cbbcd38e3bea3de71d4c /sys/arch/mvme68k | |
parent | e992baf34a7d09967be6b437c6413b990896c5fd (diff) |
wdsc driver hacked from amiga driver by Steve Woodford
Diffstat (limited to 'sys/arch/mvme68k')
-rw-r--r-- | sys/arch/mvme68k/conf/GENERIC | 6 | ||||
-rw-r--r-- | sys/arch/mvme68k/conf/MVME147 | 6 | ||||
-rw-r--r-- | sys/arch/mvme68k/conf/MVME162 | 6 | ||||
-rw-r--r-- | sys/arch/mvme68k/conf/MVME167 | 6 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/dmavar.h | 30 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/sbic.c | 4439 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/sbicreg.h | 465 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/sbicvar.h | 287 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/wdsc.c | 349 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/wdscreg.h | 53 |
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 |