-/* $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.
*
* 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.
* 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>
#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);
}
/*
*/
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);
}
/*
*/
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;
}
/*
* 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]);
}
/*
* 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