summaryrefslogtreecommitdiff
path: root/sys/arch/mvme68k/dev/sbic.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/mvme68k/dev/sbic.c')
-rw-r--r--sys/arch/mvme68k/dev/sbic.c2678
1 files changed, 0 insertions, 2678 deletions
diff --git a/sys/arch/mvme68k/dev/sbic.c b/sys/arch/mvme68k/dev/sbic.c
deleted file mode 100644
index baf80c6b4a7..00000000000
--- a/sys/arch/mvme68k/dev/sbic.c
+++ /dev/null
@@ -1,2678 +0,0 @@
-/* $OpenBSD: sbic.c,v 1.29 2010/11/18 21:13:19 miod Exp $ */
-/* $NetBSD: sbic.c,v 1.2 1996/04/23 16:32:54 chuck Exp $ */
-
-/*
- * 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.
- *
- * This code is derived from software contributed to Berkeley by
- * Van Jacobson of Lawrence Berkeley Laboratory.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)scsi.c 7.5 (Berkeley) 5/4/91
- */
-
-/*
- * 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 <sys/systm.h>
-#include <sys/device.h>
-#include <sys/kernel.h> /* For hz */
-#include <sys/disklabel.h>
-#include <sys/buf.h>
-#include <sys/queue.h>
-#include <scsi/scsi_all.h>
-#include <scsi/scsiconf.h>
-#include <uvm/uvm_extern.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>
-
-
-/*
- * 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 */
-
-/*
- * Convenience macro for waiting for a particular sbic event
- */
-#define SBIC_WAIT(regs, until, timeo) sbicwait(regs, until, timeo, __LINE__)
-
-int sbicicmd(struct sbic_softc *, void *, int, void *, int);
-int sbicgo(struct sbic_softc *, struct scsi_xfer *);
-int sbicdmaok(struct sbic_softc *, struct scsi_xfer *);
-int sbicwait(sbic_regmap_p, u_char, int , int);
-int sbiccheckdmap(void *, u_long, u_long);
-u_char sbicselectbus(struct sbic_softc *);
-int sbicxfout(sbic_regmap_p, int, void *);
-int sbicxfin(sbic_regmap_p, int, void *);
-int sbicfromscsiperiod(struct sbic_softc *, int);
-int sbictoscsiperiod(struct sbic_softc *, int);
-int sbicintr(struct sbic_softc *);
-int sbicpoll(struct sbic_softc *);
-int sbicnextstate(struct sbic_softc *, u_char, u_char);
-int sbicmsgin(struct sbic_softc *);
-int sbicabort(struct sbic_softc *, char *);
-void sbicxfdone(struct sbic_softc *);
-void sbicerror(struct sbic_softc *,u_char);
-void sbicreset(struct sbic_softc *);
-void sbic_scsidone(struct sbic_acb *, int);
-void sbic_sched(struct sbic_softc *);
-void sbic_save_ptrs(struct sbic_softc *);
-void sbic_load_ptrs(struct sbic_softc *);
-void sbicinit(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;
-
-/*
- * was broken before.. now if you want this you get it for all drives
- * on sbic controllers.
- */
-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
-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; /* 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(struct sbic_softc *dev);
-
-#else
-#define QPRINTF(a) /* */
-#endif
-
-/*
- * Save DMA pointers. Take into account partial transfer. Shut down DMA.
- */
-void
-sbic_save_ptrs(dev)
- struct sbic_softc *dev;
-{
- 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 ( data_pointer_debug )
- printf("save at (%x,%x):%x\n",
- dev->sc_cur->dc_addr, dev->sc_cur->dc_count,count);
- sbicdma_saves++;
-#endif
-
- splx(s);
-}
-
-
-/*
- * DOES NOT RESTART DMA!!!
- */
-void
-sbic_load_ptrs(dev)
- struct sbic_softc *dev;
-{
- struct sbic_acb *acb = dev->sc_nexus;
- int s;
-
- if ( acb->sc_kv.dc_count == 0 ) {
- /*
- * No data to xfer
- */
- return;
- }
-
- s = splbio();
-
- /*
- * Reset the Scatter-Gather chain
- */
- dev->sc_last = dev->sc_cur = &acb->sc_pa;
-
- /*
- * Restore the Transfer Count and DMA specific data
- */
- dev->sc_tcnt = acb->sc_tcnt;
- dev->sc_dmacmd = acb->sc_dmacmd;
-
-#ifdef DEBUG
- 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_t)vaddr);
-
- for (count = (NBPG - ((int)vaddr & PGOFSET));
- count < acb->sc_kv.dc_count &&
- (char *)kvtop((vaddr_t)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("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);
-}
-
-/*
- * used by specific sbic controller
- *
- * it appears that the higher level code does nothing with LUN's
- * so I will too. I could plug it in, however so could they
- * in scsi_scsi_cmd().
- */
-void
-sbic_scsicmd(xs)
- struct scsi_xfer *xs;
-{
- struct scsi_link *slp = xs->sc_link;
- struct sbic_softc *dev = slp->adapter_softc;
- struct sbic_acb *acb;
- int flags = xs->flags,
- s;
-
- if ( dev->sc_nexus && (flags & SCSI_POLL) )
- panic("sbic_scsicmd: busy");
-
- s = splbio();
-
- if ( (acb = TAILQ_FIRST(&dev->free_list)) != NULL )
- TAILQ_REMOVE(&dev->free_list, acb, chain);
-
- splx(s);
-
- if ( acb == NULL ) {
-#ifdef DEBUG
- printf("sbic_scsicmd: unable to queue request for target %d\n",
- slp->target);
-#ifdef DDB
- Debugger();
-#endif
-#endif
- xs->error = XS_NO_CCB;
- scsi_done(xs);
- return;
- }
-
- 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((vaddr_t)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;
- }
-
- 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);
-}
-
-/*
- * attempt to start the next available command
- */
-void
-sbic_sched(dev)
- struct sbic_softc *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...
- */
- TAILQ_FOREACH(acb, &dev->ready_list, chain) {
- 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);
-#endif
-
- 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 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);
-#ifdef DDB
- Debugger();
-#endif
- return;
- }
-#endif
-
- /*
- * 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");
-#endif
-
- 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);
-#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((vaddr_t)&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\n", xs->sense.flags);
-#endif
-
- } else {
- xs->resid = 0; /* XXXX */
- }
-
- /*
- * 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 ( !TAILQ_EMPTY(&dev->ready_list) )
- dosched = 1; /* start next command */
-
- } else
- if (TAILQ_LAST(&dev->ready_list, acb_list) == TAILQ_NEXT(acb, chain)) {
-
- TAILQ_REMOVE(&dev->ready_list, acb, chain);
-
- } else {
-
- register struct sbic_acb *a;
-
- TAILQ_FOREACH(a, &dev->nexus_list, chain) {
- if ( a == acb ) {
- TAILQ_REMOVE(&dev->nexus_list, acb, chain);
- dev->sc_tinfo[slp->target].lubusy &= ~(1 << slp->lun);
- break;
- }
- }
-
- if ( a )
- ;
- else if ( TAILQ_NEXT(acb, chain) != NULL) {
- TAILQ_REMOVE(&dev->ready_list, acb, chain);
- } else {
- printf("%s: can't find matching acb\n", dev->sc_dev.dv_xname);
-#ifdef DDB
- Debugger();
-#endif
- }
- }
-
- /*
- * Put it on the free list.
- */
- acb->flags = ACB_FREE;
- TAILQ_INSERT_HEAD(&dev->free_list, acb, chain);
-
- dev->sc_tinfo[slp->target].cmds++;
-
- scsi_done(xs);
-
- if ( dosched )
- sbic_sched(dev);
-}
-
-int
-sbicdmaok(dev, xs)
- struct sbic_softc *dev;
- struct scsi_xfer *xs;
-{
- 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;
- u_char until;
- int timeo;
- int line;
-{
- u_char val;
-
- if ( timeo == 0 )
- timeo = 1000000; /* some large value.. */
-
- GET_SBIC_asr(regs, val);
-
- while ( (val & until) == 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);
-}
-
-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 SBIC_STATE_ERROR;
- }
-
- 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 SBIC_STATE_ERROR;
-}
-
-
-/*
- * Initialize driver-private structures
- */
-void
-sbicinit(dev)
- struct sbic_softc *dev;
-{
- u_int i;
-
- extern u_long scsi_nosync;
- extern int shift_nosync;
-
- if ( (dev->sc_flags & SBICF_ALIVE) == 0 ) {
-
- struct sbic_acb *acb;
-
- 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));
-
-#ifdef DEBUG
- /*
- * make sure timeout is really not needed
- */
- timeout((void *)sbictimeout, dev, 30 * hz);
-#endif
-
- } else
- panic("sbic: reinitializing driver!");
-
- dev->sc_flags |= SBICF_ALIVE;
- dev->sc_flags &= ~SBICF_SELECTED;
-
- /*
- * initialize inhibit array
- */
- if ( scsi_nosync ) {
-
- u_int inhibit_sync = (scsi_nosync >> shift_nosync) & 0xff;
-
- shift_nosync += 8;
-
-#ifdef DEBUG
- 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;
- }
- }
-
- sbicreset(dev);
-}
-
-void
-sbicreset(dev)
- struct sbic_softc *dev;
-{
- 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;
-}
-
-void
-sbicerror(dev, csr)
- struct sbic_softc *dev;
- u_char csr;
-{
- struct scsi_xfer *xs = dev->sc_xs;
-
-#ifdef DIAGNOSTIC
- if ( xs == NULL )
- panic("sbicerror: dev->sc_xs == NULL");
-#endif
-
- if ( xs->flags & SCSI_SILENT )
- return;
-
- printf("%s: csr == 0x%02x\n", dev->sc_dev.dv_xname, csr);
-}
-
-/*
- * 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));
-
- 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 separate 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 initiate a selection...
- */
- if ( !sbic_enable_reselect && TAILQ_EMPTY(&dev->nexus_list))
- 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 definitely 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
- 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 ( sync_debug )
- printf ("sent\n");
-#endif
- }
-
- /*
- * There's one interrupt still to come: the change to CMD phase...
- */
- SBIC_WAIT(regs, SBIC_ASR_INT , 0);
- GET_SBIC_csr(regs, csr);
- }
-
- /*
- * set sync or async
- */
- if ( dev->sc_sync[target].state == SYNC_DONE ) {
-#ifdef DEBUG
- if ( sync_debug )
- printf("select(%d): sync reg = 0x%02x\n", target,
- SBIC_SYN(dev->sc_sync[target].offset,
- dev->sc_sync[target].period));
-#endif
- SET_SBIC_syn(regs, SBIC_SYN(dev->sc_sync[target].offset,
- dev->sc_sync[target].period));
- } else {
-#ifdef DEBUG
- if ( sync_debug )
- printf("select(%d): sync reg = 0x%02x\n", target,
- SBIC_SYN(0,sbic_min_period));
-#endif
- SET_SBIC_syn(regs, SBIC_SYN(0, sbic_min_period));
- }
-
- return csr;
-}
-
-/*
- * Information Transfer *to* a Scsi Target.
- *
- * Note: Don't expect there to be an interrupt immediately after all
- * the data is transferred out. The WD spec sheet says that the Transfer-
- * Info command for non-MSG_IN phases only completes when the target
- * next asserts 'REQ'. That is, when the SCSI bus changes to a new state.
- *
- * This can have a nasty effect on commands which take a relatively long
- * time to complete, for example a START/STOP unit command may remain in
- * CMD phase until the disk has spun up. Only then will the target change
- * to STATUS phase. This is really only a problem for immediate commands
- * since we don't allow disconnection for them (yet).
- */
-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 ( len && (asr & SBIC_ASR_INT) == 0 && wait-- > 0 );
-
-#ifdef DEBUG
- QPRINTF(("sbicxfout done: %d bytes remaining (wait:%d)\n", len, wait));
-#endif
-
- /*
- * Normally, an interrupt will be pending when this routing returns.
- */
- 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;
-}
-
-/*
- * SCSI 'immediate' command: issue a command to some SCSI device
- * and get back an 'immediate' response (i.e., do programmed xfer
- * to get the response data). 'cbuf' is a buffer containing a scsi
- * command of length clen bytes. 'buf' is a buffer of length 'len'
- * bytes for data. The transfer direction is determined by the device
- * (i.e., by the scsi bus data xfer phase). If 'len' is zero, the
- * command must supply no data.
- *
- * Note that although this routine looks like it can handle disconnect/
- * reselect, the fact is that it can't. There is still some work to be
- * done to clean this lot up.
- */
-int
-sbicicmd(dev, cbuf, clen, buf, len)
- struct sbic_softc *dev;
- void *cbuf,
- *buf;
- int clen,
- len;
-{
- sbic_regmap_p regs = dev->sc_sbicp;
- struct sbic_acb *acb = dev->sc_nexus;
- u_char csr,
- asr;
- int still_busy = SBIC_STATE_RUNNING;
-#ifdef DEBUG
- int counter = 0;
-#endif
-
- /*
- * 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 &&
- still_busy != SBIC_STATE_DISCONNECT ) {
- if ( (csr = sbicselectbus(dev)) == 0 ) {
- dev->sc_flags &= ~SBICF_ICMD;
- return(-1);
- }
- } else
- if ( (asr & (SBIC_ASR_BSY | SBIC_ASR_INT)) == SBIC_ASR_INT )
- GET_SBIC_csr(regs, csr);
- else
- csr = 0;
-
- if ( 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 = SBIC_STATE_DONE; /* done */
- } else {
-#ifdef DEBUG
- 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 (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 ( still_busy >= SBIC_STATE_RUNNING ) /* Bsy */
- SBIC_WAIT (regs, SBIC_ASR_INT, sbic_cmd_wait);
-
- /*
- * do it again
- */
- } while ( still_busy >= SBIC_STATE_RUNNING && 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, dev->lun,
- acb->sc_kv.dc_count,
- dev->sc_stat[0]);
-#endif
-
- dev->sc_flags &= ~SBICF_ICMD;
-
- return(dev->sc_stat[0]);
-}
-
-/*
- * Finish SCSI xfer command: After the completion interrupt from
- * a read/write operation, sequence through the final phases in
- * programmed i/o. This routine is a lot like sbicicmd except we
- * skip (and don't allow) the select, cmd out and data in/out phases.
- */
-void
-sbicxfdone(dev)
- struct sbic_softc *dev;
-{
- 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 {
-
- 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_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;
-
- usedma = sbicdmaok(dev, xs);
-
-#ifdef DEBUG
- if ( data_pointer_debug > 1 )
- printf("sbicgo(%d,%d): usedma=%d\n", dev->target, dev->lun, usedma);
-#endif
-
- /*
- * 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((vaddr_t)addr) != acb->sc_pa.dc_addr) ) {
- printf("sbic: DMA buffer mapping changed %p->%lx\n",
- acb->sc_pa.dc_addr, kvtop((vaddr_t)addr));
-#ifdef DDB
- Debugger();
-#endif
- }
-
-#ifdef DEBUG
- ++sbicdma_ops; /* count total DMA operations */
-#endif
-
- /*
- * 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
- dev->sc_dmatimo = dev->sc_tcnt ? 1 : 0;
-#endif
- } else
- dev->sc_dmacmd = 0; /* Don't use DMA */
-
- acb->sc_dmacmd = dev->sc_dmacmd;
-
-#ifdef DEBUG
- 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
-
- /*
- * Lets cycle a while then let the interrupt handler take over.
- */
- GET_SBIC_asr(regs, asr);
-
- do {
-
- QPRINTF(("go "));
-
- /*
- * 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);
-
- if ( asr & SBIC_ASR_LCI )
- printf("sbicgo: LCI asr:%02x csr:%02x\n", asr, csr);
-
- if ( asr & SBIC_ASR_INT )
- GET_SBIC_csr(regs, csr);
- }
-
- } while ( i == SBIC_STATE_RUNNING && asr & (SBIC_ASR_INT|SBIC_ASR_LCI) );
-
- if ( i == SBIC_STATE_DONE ) {
- if ( dev->sc_stat[0] == 0xff )
-#if 0
- printf("sbicgo: done & stat = 0xff\n");
-#else
- ;
-#endif
- else
- return 1; /* Did we really finish that fast? */
- }
-
- return 0;
-}
-
-
-int
-sbicintr(dev)
- struct sbic_softc *dev;
-{
- sbic_regmap_p regs = dev->sc_sbicp;
- u_char asr,
- csr;
- int i;
-
- /*
- * pending interrupt?
- */
- GET_SBIC_asr (regs, asr);
- if ( (asr & SBIC_ASR_INT) == 0 )
- return(0);
-
- GET_SBIC_csr(regs, csr);
-
- do {
-
- QPRINTF(("intr[0x%x]", csr));
-
- i = sbicnextstate(dev, csr, asr);
-#if 0
- WAIT_CIP(regs);
-#endif
- if ( i == SBIC_STATE_RUNNING ) {
- GET_SBIC_asr(regs, asr);
-
- if ( asr & SBIC_ASR_LCI )
- printf("sbicgo: LCI asr:%02x csr:%02x\n", asr, csr);
-
- if ( asr & SBIC_ASR_INT )
- GET_SBIC_csr(regs, csr);
- }
-
- } 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.
- * 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;
-{
- sbic_regmap_p regs = dev->sc_sbicp;
- u_char asr,
- csr = 0;
- int i;
-
- /*
- * Wait for the next interrupt
- */
- SBIC_WAIT(regs, SBIC_ASR_INT, sbic_cmd_wait);
-
- do {
- GET_SBIC_asr (regs, asr);
-
- if ( asr & SBIC_ASR_INT )
- GET_SBIC_csr(regs, csr);
-
- QPRINTF(("poll[0x%x]", csr));
-
- /*
- * 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 ) {
- u_char z = 0;
-
- if ( asr & SBIC_ASR_DBR ) {
- printf("sbipoll: 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, z);
- GET_SBIC_asr(regs, asr);
-
- if ( asr & SBIC_ASR_DBR ) /* Wants us to write */
- SET_SBIC_data(regs, z);
- }
-
- GET_SBIC_asr(regs, asr);
- }
-
- if ( asr & SBIC_ASR_LCI )
- printf("sbicpoll: LCI asr:%02x csr:%02x\n", asr,csr);
- else
- if ( i == SBIC_STATE_RUNNING ) /* 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;
-{
- sbic_regmap_p regs = dev->sc_sbicp;
- int recvlen = 1;
- u_char asr,
- csr,
- *tmpaddr,
- *msgaddr;
-
- tmpaddr = msgaddr = dev->sc_msg;
-
- tmpaddr[0] = 0xff;
- tmpaddr[1] = 0xff;
-
- GET_SBIC_asr(regs, asr);
-
-#ifdef DEBUG
- if ( reselect_debug > 1 )
- printf("sbicmsgin asr=%02x\n", asr);
-#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\n", *tmpaddr, csr);
-#endif
-
- 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 ) {
- 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);
-#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 ( 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 && 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", 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));
-#ifdef DEBUG
- if ( sync_debug )
- printf("msgin(%d): sync reg = 0x%02x\n", dev->target,
- SBIC_SYN(dev->sc_sync[dev->target].offset,
- dev->sc_sync[dev->target].period));
-#endif
-
- 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", 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:
- * SBIC_STATE_DONE == done
- * SBIC_STATE_RUNNING == working
- * SBIC_STATE_DISCONNECT == disconnected
- * SBIC_STATE_ERROR == error
- */
-int
-sbicnextstate(dev, csr, asr)
- struct sbic_softc *dev;
- u_char csr,
- asr;
-{
- 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
- 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 > 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
- 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");
-#endif
-
- 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);
-#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;
-
- 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(10);
- }
-
- /*
- * If we didn't get an interrupt, somethink's up
- */
- if ( (asr & SBIC_ASR_INT) == 0 ) {
- printf("%s: Reselect without identify? asr %x\n",
- dev->sc_dev.dv_xname, asr);
- 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 ) {
- /*
- * 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");
- }
-#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...
- */
- TAILQ_FOREACH(acb, &dev->nexus_list, chain) {
-
- 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 %p\n",
- dev->sc_dev.dv_xname,
- csr == SBIC_CSR_RSLT_NI ? "NI" : "IFY", newtarget,
- &TAILQ_FIRST(&dev->nexus_list));
- 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("next: aborting asr 0x%02x csr 0x%02x\n", asr, csr);
-
-#ifdef DDB
- Debugger();
-#endif
-
-#ifdef DEBUG
- 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);
- 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
- 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
- sbic_scsidone(acb, -1);
- }
-
- return SBIC_STATE_ERROR;
- }
- }
-
- 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;
-{
- u_char *buffer;
- u_long phy_buf;
- u_long phy_len;
-
- buffer = bp;
-
- if ( len == 0 )
- return(1);
-
- while ( len ) {
-
- phy_buf = kvtop((vaddr_t)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, 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(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, p)
- struct sbic_softc *dev;
- int p;
-{
- 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 */
-
- 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++;
-
- return( (ret >= 8) ? 0 : ret );
-}
-
-#ifdef DEBUG
-void
-sbictimeout(dev)
- struct sbic_softc *dev;
-{
- int s,
- asr;
-
- s = splbio();
-
- if ( dev->sc_dmatimo ) {
-
- 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);
- } else {
- (void) sbicabort(dev, "timeout");
- splx(s);
- return;
- }
- }
-
- dev->sc_dmatimo++;
- }
-
- splx(s);
-
- timeout((void *)sbictimeout, dev, 30 * hz);
-}
-#endif