summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/sparc/dev/dma.c415
-rw-r--r--sys/arch/sparc/dev/dmareg.h83
-rw-r--r--sys/arch/sparc/dev/dmavar.h73
-rw-r--r--sys/arch/sparc/dev/esp.c1946
-rw-r--r--sys/arch/sparc/dev/espreg.h255
-rw-r--r--sys/arch/sparc/dev/espvar.h298
6 files changed, 1700 insertions, 1370 deletions
diff --git a/sys/arch/sparc/dev/dma.c b/sys/arch/sparc/dev/dma.c
index 1a88992dd2e..dfb0f2a3e9b 100644
--- a/sys/arch/sparc/dev/dma.c
+++ b/sys/arch/sparc/dev/dma.c
@@ -1,7 +1,9 @@
-/* $NetBSD: dma.c,v 1.10 1995/08/18 10:43:49 pk Exp $ */
+/* $NetBSD: dma.c,v 1.8 1995/02/01 12:37:21 pk Exp $ */
/*
* Copyright (c) 1994 Peter Galbavy. All rights reserved.
+ * Copyright (c) 1995 Theo de Raadt. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -12,7 +14,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by Peter Galbavy.
+ * This product includes software developed by Peter Galbavy and
+ * Theo de Raadt.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -47,19 +50,20 @@
#include <scsi/scsiconf.h>
#include <sparc/dev/sbusvar.h>
+#include <sparc/dev/sbusreg.h>
#include <sparc/dev/dmareg.h>
#include <sparc/dev/dmavar.h>
#include <sparc/dev/espreg.h>
#include <sparc/dev/espvar.h>
-int dmaprint __P((void *, char *));
+#include <sparc/sparc/cache.h>
+
+/*#define DMA_TEST*/
+
+extern int sbus_print __P((void *, char *));
+
void dmaattach __P((struct device *, struct device *, void *));
int dmamatch __P((struct device *, void *, void *));
-void dma_reset __P((struct dma_softc *));
-void dma_enintr __P((struct dma_softc *));
-int dma_isintr __P((struct dma_softc *));
-void dma_start __P((struct dma_softc *, caddr_t *, size_t *, int));
-int dmaintr __P((struct dma_softc *));
struct cfdriver dmacd = {
NULL, "dma", dmamatch, dmaattach,
@@ -67,29 +71,21 @@ struct cfdriver dmacd = {
};
struct cfdriver ledmacd = {
- NULL, "ledma", matchbyname, dmaattach,
+ NULL, "ledma", dmamatch, dmaattach,
DV_DULL, sizeof(struct dma_softc)
};
struct cfdriver espdmacd = {
- NULL, "espdma", matchbyname, dmaattach,
+ NULL, "espdma", dmamatch, dmaattach,
DV_DULL, sizeof(struct dma_softc)
};
int
-dmaprint(aux, name)
- void *aux;
- char *name;
-{
- return -1;
-}
-
-int
dmamatch(parent, vcf, aux)
- struct device *parent;
- void *vcf, *aux;
+ struct device *parent;
+ void *vcf, *aux;
{
- struct cfdata *cf = vcf;
+ struct cfdata *cf = vcf;
register struct confargs *ca = aux;
register struct romaux *ra = &ca->ca_ra;
@@ -106,17 +102,16 @@ dmamatch(parent, vcf, aux)
*/
void
dmaattach(parent, self, aux)
- struct device *parent, *self;
- void *aux;
+ struct device *parent, *self;
+ void *aux;
{
register struct confargs *ca = aux;
- struct dma_softc *sc = (void *)self;
- int node, base, slot;
- char *name;
+ struct confargs oca;
+ struct dma_softc *sc = (void *)self;
+ int node, base, slot;
+ char *name;
- /*
- * do basic sbus stuff (I think)
- */
+ /* XXX modifying ra_vaddr is bad! */
if (ca->ca_ra.ra_vaddr == NULL)
ca->ca_ra.ra_vaddr = mapiodev(ca->ca_ra.ra_paddr,
ca->ca_ra.ra_len, ca->ca_bustype);
@@ -125,133 +120,156 @@ dmaattach(parent, self, aux)
sc->sc_regs = (struct dma_regs *) ca->ca_ra.ra_vaddr;
/*
- * find the ESP by poking around the esp device structures
- *
* What happens here is that if the esp driver has not been
* configured, then this returns a NULL pointer. Then when the
* esp actually gets configured, it does the opposing test, and
* if the sc->sc_dma field in it's softc is NULL, then tries to
* find the matching dma driver.
- *
*/
sc->sc_esp = ((struct esp_softc *)
getdevunit("esp", sc->sc_dev.dv_unit));
-
- /*
- * and a back pointer to us, for DMA
- */
if (sc->sc_esp)
sc->sc_esp->sc_dma = sc;
printf(": rev ");
sc->sc_rev = sc->sc_regs->csr & D_DEV_ID;
switch (sc->sc_rev) {
- case DMAREV_0:
- printf("0");
+ case DMAREV_4300:
+ printf("4/300\n");
break;
case DMAREV_1:
- printf("1");
+ printf("1\n");
+ break;
+ case DMAREV_ESC1:
+ printf("ESC1\n");
break;
case DMAREV_PLUS:
- printf("1+");
+ printf("1+\n");
break;
case DMAREV_2:
- printf("2");
+ printf("2\n");
break;
default:
- printf("unknown");
+ printf("unknown\n");
}
- printf("\n");
- /* indirect functions */
- sc->enintr = dma_enintr;
- sc->isintr = dma_isintr;
- sc->reset = dma_reset;
- sc->start = dma_start;
- sc->intr = dmaintr;
-
- sc->sc_node = ca->ca_ra.ra_node;
#if defined(SUN4C) || defined(SUN4M)
- if (ca->ca_bustype == BUS_SBUS)
+ if (ca->ca_bustype == BUS_SBUS) {
+ sc->sc_node = ca->ca_ra.ra_node;
sbus_establish(&sc->sc_sd, &sc->sc_dev);
-#endif /* SUN4C || SUN4M */
-#ifdef notyet
- /* return if we are a plain "dma" with no children */
- if (strcmp(getpropstring(node, "name"), "dma") == 0)
- return;
-
- /* search through children */
- for (node = firstchild(sc->sc_node); node; node = nextsibling(node)) {
- name = getpropstring(node, "name");
- if (!romprop(&ca->ca_ra, name, node))
- continue;
- base = (int)ca->ca_ra.ra_paddr;
- if (SBUS_ABS(base)) {
- ca->ca_slot = SBUS_ABS_TO_SLOT(base);
- ca->ca_offset = SBUS_ABS_TO_OFFSET(base);
- } else {
- ca->ca_slot = slot = ca->ca_ra.ra_iospace;
- ca->ca_offset = base;
- ca->ca_ra.ra_paddr = (void *)SBUS_ADDR(slot, base);
+ /*
+ * If the device is in an SBUS slave slot, report
+ * it (but we don't care, because the corresponding
+ * ESP will also realize the same thing.)
+ */
+ (void) sbus_slavecheck(self, ca);
+
+ /*
+ * if our name is not "dma", we may have subdevices
+ * below us in the device tree (like an esp)
+ * XXX: TDR: should we do this even if it is "dma"?
+ */
+ if (strcmp(ca->ca_ra.ra_name, "dma") == 0)
+ return;
+
+ /* search through children */
+ for (node = firstchild(sc->sc_node); node;
+ node = nextsibling(node)) {
+ name = getpropstring(node, "name");
+ if (!romprop(&oca.ca_ra, name, node))
+ continue;
+
+ /*
+ * advance bootpath if it currently points to us
+ * XXX There appears to be strangeness in the unit
+ * number on at least one espdma system (SS5 says
+ * espdma5, but nothing is available to compare
+ * against that digit 5...
+ */
+ if (ca->ca_ra.ra_bp &&
+ !strcmp(ca->ca_ra.ra_bp->name, ca->ca_ra.ra_name) &&
+ ca->ca_ra.ra_bp->val[1] == (int)ca->ca_ra.ra_paddr)
+ oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1;
+ else
+ oca.ca_ra.ra_bp = NULL;
+
+ base = (int)oca.ca_ra.ra_paddr;
+ if (SBUS_ABS(base)) {
+ oca.ca_slot = SBUS_ABS_TO_SLOT(base);
+ oca.ca_offset = SBUS_ABS_TO_OFFSET(base);
+ } else {
+ oca.ca_slot = slot = ca->ca_ra.ra_iospace;
+ oca.ca_offset = base;
+ oca.ca_ra.ra_paddr = (void *)SBUS_ADDR(slot, base);
+ }
+ oca.ca_bustype = BUS_SBUS;
+ (void) config_found(&sc->sc_dev, (void *)&oca, sbus_print);
}
- (void) config_found(&sc->sc_dev, (void *)&ca, dmaprint);
+
}
-#endif
+#endif /* SUN4C || SUN4M */
}
void
-dma_reset(sc)
- struct dma_softc *sc;
+dmareset(sc)
+ struct dma_softc *sc;
{
- DMAWAIT1(sc); /* let things drain */
+ DMAWAIT_PEND(sc);
DMACSR(sc) |= D_RESET; /* reset DMA */
DELAY(200); /* what should this be ? */
DMACSR(sc) &= ~D_RESET; /* de-assert reset line */
- DMACSR(sc) |= D_INT_EN; /* enable interrupts */
- if (sc->sc_rev > DMAREV_1)
- DMACSR(sc) |= D_FASTER;
- sc->sc_active = 0; /* and of course we aren't */
-}
+ switch (sc->sc_rev) {
+ case DMAREV_1:
+ case DMAREV_4300:
+ case DMAREV_ESC1:
+ break;
+ case DMAREV_PLUS:
+ case DMAREV_2:
+ if (sc->sc_esp->sc_rev >= ESP100A)
+ DMACSR(sc) |= D_FASTER;
+ break;
+ }
-void
-dma_enintr(sc)
- struct dma_softc *sc;
-{
- sc->sc_regs->csr |= D_INT_EN;
+ sc->sc_active = 0; /* and of course we aren't */
}
int
-dma_isintr(sc)
+dmapending(sc)
struct dma_softc *sc;
{
return (sc->sc_regs->csr & (D_INT_PEND|D_ERR_PEND));
}
-#define ESPMAX ((sc->sc_esp->sc_rev > ESP100A) ? \
- (16 * 1024 * 1024) : (64 * 1024))
-#define DMAMAX(a) (0x01000000 - ((a) & 0x00ffffff))
+/* bytes between loc and the end of this 16M region of memory */
+#define DMAMAX(loc) (0x01000000 - ((loc) & 0x00ffffff))
+
+#define ESPMAX ((sc->sc_esp->sc_rev > ESP100A) ? \
+ (16 * 1024 * 1024) : (64 * 1024))
-/*!!!*/int xdmadebug = 0;
/*
- * start a dma transfer or keep it going
+ * Start a dma transfer or keep it going.
+ * We do the loading of the transfer counter.
+ * XXX: what about write-back caches?
*/
void
-dma_start(sc, addr, len, datain)
- struct dma_softc *sc;
- caddr_t *addr;
- size_t *len;
- int datain;
+dmastart(sc, addr, len, datain, poll)
+ struct dma_softc *sc;
+ void *addr;
+ size_t *len;
+ int datain, poll;
{
- /* we do the loading of the transfer counter */
- volatile caddr_t esp = sc->sc_esp->sc_reg;
- size_t size;
+ struct espregs *espr = sc->sc_esp->sc_regs;
+ int size;
+
+ if (sc->sc_active)
+ panic("dma: dmastart() called while active\n");
sc->sc_dmaaddr = addr;
sc->sc_dmalen = len;
-
- ESP_DMA(("%s: start %d@0x%08x,%d\n", sc->sc_dev.dv_xname, *sc->sc_dmalen, *sc->sc_dmaaddr, datain ? 1 : 0));
+ sc->sc_dmapolling = poll;
+ sc->sc_dmadev2mem = datain;
/*
* the rules say we cannot transfer more than the limit
@@ -260,108 +278,177 @@ dma_start(sc, addr, len, datain)
*/
size = min(*sc->sc_dmalen, ESPMAX);
size = min(size, DMAMAX((size_t) *sc->sc_dmaaddr));
- sc->sc_dmasize = size;
-
- ESP_DMA(("dma_start: dmasize = %d\n", sc->sc_dmasize));
-
- esp[ESP_TCL] = size;
- esp[ESP_TCM] = size >> 8;
- if (sc->sc_esp->sc_rev > ESP100A) {
- esp[ESP_TCH] = size >> 16;
- }
- /* load the count in */
- ESPCMD(sc->sc_esp, ESPCMD_NOP|ESPCMD_DMA);
+ sc->sc_segsize = size;
+
+#ifdef DMA_TEST
+ printf("%s: start %d@0x%08x [%s scsi] [chunk=%d] %d\n",
+ sc->sc_dev.dv_xname,
+ *sc->sc_dmalen, *sc->sc_dmaaddr,
+ datain ? "read from" : "write to",
+ sc->sc_segsize, poll);
+#endif
- DMAWAIT1(sc);
-
- /* clear errors and D_TC flag */
- DMACSR(sc) |= D_INVALIDATE;
- DMAWAIT1(sc);
+ espr->espr_tcl = size;
+ espr->espr_tcm = size >> 8;
+ if (sc->sc_esp->sc_rev > ESP100A)
+ espr->espr_tch = size >> 16;
+ espr->espr_cmd = ESPCMD_DMA|ESPCMD_NOP; /* load the count in */
DMADDR(sc) = *sc->sc_dmaaddr;
- DMACSR(sc) |= datain|D_EN_DMA|D_INT_EN;
+ DMACSR(sc) = (DMACSR(sc) & ~(D_WRITE|D_INT_EN)) | D_EN_DMA |
+ (datain ? D_WRITE : 0) | (poll ? 0 : D_INT_EN);
- /* and clear from last read if this is a write */
- if (!datain)
- DMACSR(sc) &= ~D_WRITE;
-
- /*
- * and kick the SCSI
- * Note that if `size' is 0, we've already transceived all
- * the bytes we want but we're still in the DATA PHASE.
- * Apparently, the device needs padding. Also, a transfer
- * size of 0 means "maximum" to the chip DMA logic.
- */
- ESPCMD(sc->sc_esp, (size==0?ESPCMD_TRPAD:ESPCMD_TRANS)|ESPCMD_DMA);
+ /* and kick the SCSI */
+ espr->espr_cmd = ESPCMD_DMA|ESPCMD_TRANS;
sc->sc_active = 1;
}
/*
* Pseudo (chained) interrupt from the esp driver to kick the
- * current running DMA transfer. I am replying on espintr() to
- * pickup and clean errors for now
+ * current running DMA transfer. espintr() cleans up errors.
*
- * return 1 if it was a DMA continue.
+ * return 1 if a dma operation is being continued (for when all
+ * the data could not be transferred in one dma operation).
*/
int
-dmaintr(sc)
- struct dma_softc *sc;
+dmaintr(sc, restart)
+ struct dma_softc *sc;
+ int restart;
{
- volatile caddr_t esp = sc->sc_esp->sc_reg;
- int trans = 0, resid = 0;
+ struct espregs *espr = sc->sc_esp->sc_regs;
+ int trans = 0, resid;
- ESP_DMA(("%s: intr\n", sc->sc_dev.dv_xname));
+#ifdef DMA_TEST
+ printf("%s: intr\n", sc->sc_dev.dv_xname);
+#endif
if (DMACSR(sc) & D_ERR_PEND) {
printf("%s: error", sc->sc_dev.dv_xname);
+ if (sc->sc_rev == DMAREV_4300)
+ DMAWAIT_PEND(sc);
DMACSR(sc) |= D_INVALIDATE;
- return 0;
+ return (0);
}
- /* This is an "assertion" :) */
if (sc->sc_active == 0)
panic("dmaintr: DMA wasn't active");
- /* DMA has stopped */
+ /* DMA has stopped, but flush it first */
+ dmadrain(sc);
+ if (DMACSR(sc) & D_DRAINING)
+ printf("drain failed %d left\n", DMACSR(sc) & D_DRAINING);
DMACSR(sc) &= ~D_EN_DMA;
sc->sc_active = 0;
- if (sc->sc_dmasize == 0) {
- /* A "Transfer Pad" operation completed */
- ESP_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n", esp[ESP_TCL] | (esp[ESP_TCM] << 8), esp[ESP_TCL], esp[ESP_TCM]));
- return 0;
- }
-
- if (!(DMACSR(sc) & D_WRITE) &&
- (resid = (esp[ESP_FFLAG] & ESPFIFO_FF)) != 0) {
+ /*
+ * XXX: The subtracting of resid and throwing away up to 31
+ * bytes cannot be the best/right way to do this. There's got
+ * to be a better way, such as letting the DMA take control
+ * again and putting it into memory, or pulling it out and
+ * putting it in memory by ourselves.
+ * XXX in the meantime, just do this job silently
+ */
+ resid = 0;
+ if (!sc->sc_dmadev2mem &&
+ (resid = (espr->espr_fflag & ESPFIFO_FF)) != 0) {
+#if 0
printf("empty FIFO of %d ", resid);
- ESPCMD(sc->sc_esp, ESPCMD_FLUSH);
+#endif
+ espr->espr_cmd = ESPCMD_FLUSH;
DELAY(1);
}
-
- resid += esp[ESP_TCL] | (esp[ESP_TCM] << 8) |
- (sc->sc_esp->sc_rev > ESP100A ? (esp[ESP_TCH] << 16) : 0);
- trans = sc->sc_dmasize - resid;
+ resid += espr->espr_tcl | (espr->espr_tcm << 8) |
+ (sc->sc_esp->sc_rev > ESP100A ? (espr->espr_tch << 16) : 0);
+ trans = sc->sc_segsize - resid;
if (trans < 0) { /* transferred < 0 ? */
printf("%s: xfer (%d) > req (%d)\n",
- sc->sc_dev.dv_xname, trans, sc->sc_dmasize);
- trans = sc->sc_dmasize;
+ sc->sc_dev.dv_xname, trans, sc->sc_segsize);
+ trans = sc->sc_segsize;
}
- ESP_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; resid=%d, trans=%d\n", esp[ESP_TCL],esp[ESP_TCM], esp[ESP_TCH], trans, resid));
+#ifdef DMA_TEST
+ printf("dmaintr: resid=%d, trans=%d\n", resid, trans);
+#endif
- if (DMACSR(sc) & D_WRITE)
+ if (sc->sc_dmadev2mem && vactype != VAC_NONE)
cache_flush(*sc->sc_dmaaddr, trans);
+ sc->sc_segsize -= trans;
*sc->sc_dmalen -= trans;
*sc->sc_dmaaddr += trans;
- if (*sc->sc_dmalen == 0 ||
- sc->sc_esp->sc_phase != sc->sc_esp->sc_prevphase)
- return 0;
+#ifdef DMA_TEST
+ printf("%s: %d/%d bytes left\n", sc->sc_dev.dv_xname,
+ *sc->sc_dmalen, sc->sc_segsize);
+#endif
+
+ /* completely finished with the DMA transaction */
+ if (sc->sc_segsize == 0 && *sc->sc_dmalen == 0)
+ return (0);
+ if (restart == 0)
+ return (1);
/* and again */
- dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, DMACSR(sc) & D_WRITE);
- return 1;
+ dmastart(sc, sc->sc_dmaaddr, sc->sc_dmalen, sc->sc_dmadev2mem,
+ sc->sc_dmapolling);
+ return (1);
+}
+
+/*
+ * We have to ask rev 1 and 4/300 dma controllers to drain their fifo.
+ * Apparently the other chips have drained by the time we get an
+ * interrupt, but we check anyways.
+ */
+void
+dmadrain(sc)
+ struct dma_softc *sc;
+{
+ switch (sc->sc_rev) {
+ case DMAREV_1:
+ case DMAREV_4300:
+ case DMAREV_PLUS:
+ case DMAREV_2:
+ if (DMACSR(sc) & D_DRAINING)
+ DMAWAIT_DRAIN(sc);
+ break;
+ case DMAREV_ESC1:
+ DMAWAIT_PEND(sc)
+ DMAWAIT_DRAIN(sc); /* XXX: needed? */
+ break;
+ }
+ DMACSR(sc) |= D_INVALIDATE;
+}
+
+/*
+ * XXX
+ * During autoconfig we are in polled mode and we execute some commands.
+ * eventually we execute the last polled command. esp interrupts go through
+ * the dma chip's D_INT_EN gate. thus, because we have our data, we're happy
+ * and return. the esp chip has not, however, become unbusy. as soon as we
+ * execute our first non-polled command, we find the esp state machine is
+ * non-idle. it has not finished getting off the scsi bus, because it didn't
+ * get interrupts (and the polled code has long since gone it's merry way.)
+ *
+ * therefore, whenever we finish with a polled mode command, we enable
+ * interrupts so that we can get our data. it is probably safe to do so,
+ * since the scsi transfer has happened without error. the interrupts that
+ * will happen have no bearing on the higher level scsi subsystem, since it
+ * just functions to let the esp chip "clean up" it's state.
+ */
+void
+dmaenintr(sc)
+ struct dma_softc *sc;
+{
+ DMACSR(sc) |= D_INT_EN;
+}
+
+int
+dmadisintr(sc)
+ struct dma_softc *sc;
+{
+ int x = DMACSR(sc) & D_INT_EN;
+
+ DMACSR(sc) &= ~D_INT_EN;
+ return x;
}
diff --git a/sys/arch/sparc/dev/dmareg.h b/sys/arch/sparc/dev/dmareg.h
index ced68a3c057..d19c5c2960e 100644
--- a/sys/arch/sparc/dev/dmareg.h
+++ b/sys/arch/sparc/dev/dmareg.h
@@ -2,6 +2,8 @@
/*
* Copyright (c) 1994 Peter Galbavy. All rights reserved.
+ * Copyright (c) 1995 Theo de Raadt. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -12,7 +14,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by Peter Galbavy.
+ * This product includes software developed by Peter Galbavy and
+ * Theo de Raadt.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -29,42 +32,50 @@
*/
struct dma_regs {
- volatile u_long csr; /* DMA CSR */
-#define D_INT_PEND 0x00000001 /* interrupt pending */
-#define D_ERR_PEND 0x00000002 /* error pending */
-#define D_DRAINING 0x0000000c /* fifo draining */
-#define D_INT_EN 0x00000010 /* interrupt enable */
-#define D_INVALIDATE 0x00000020 /* invalidate fifo */
-#define D_SLAVE_ERR 0x00000040 /* slave access size error */
-#define D_DRAIN 0x00000040 /* drain fifo if DMAREV_1 */
-#define D_RESET 0x00000080 /* reset scsi */
-#define D_WRITE 0x00000100 /* 1 = dev -> mem */
-#define D_EN_DMA 0x00000200 /* enable DMA requests */
-#define D_R_PEND 0x00000400 /* something only on ver < 2 */
-#define D_EN_CNT 0x00002000 /* enable byte counter */
-#define D_TC 0x00004000 /* terminal count */
-#define D_DSBL_CSR_DRN 0x00010000 /* disable fifo drain on csr */
-#define D_DSBL_SCSI_DRN 0x00020000 /* disable fifo drain on reg */
-#define D_BURST_SIZE 0x000c0000 /* sbus read/write burst size */
-#define D_DIAG 0x00100000 /* disable fifo drain on addr */
-#define D_TWO_CYCLE 0x00200000 /* 2 clocks per transfer */
-#define D_FASTER 0x00400000 /* 3 clocks per transfer */
-#define D_TCI_DIS 0x00800000 /* disable intr on D_TC */
-#define D_EN_NEXT 0x01000000 /* enable auto next address */
-#define D_DMA_ON 0x02000000 /* enable dma from scsi */
-#define D_A_LOADED 0x04000000 /* address loaded */
-#define D_NA_LOADED 0x08000000 /* next address loaded */
-#define D_DEV_ID 0xf0000000 /* device ID */
-#define DMAREV_0 0x00000000 /* Sunray DMA */
-#define DMAREV_1 0x80000000 /* 'DMA' */
-#define DMAREV_PLUS 0x90000000 /* 'DMA+' */
-#define DMAREV_2 0xa0000000 /* 'DMA2' */
+ volatile u_long csr; /* DMA CSR */
+#define D_INT_PEND 0x00000001 /* interrupt pending */
+#define D_ERR_PEND 0x00000002 /* error pending */
+#define D_DRAINING 0x0000000c /* fifo draining */
+#define D_INT_EN 0x00000010 /* interrupt enable */
+#define D_INVALIDATE 0x00000020 /* invalidate fifo */
+#define D_SLAVE_ERR 0x00000040 /* slave access size error */
+#define D_DRAIN 0x00000040 /* drain fifo if DMAREV_1 */
+#define D_RESET 0x00000080 /* reset scsi */
+#define D_WRITE 0x00000100 /* 1 = dev -> mem */
+#define D_EN_DMA 0x00000200 /* enable DMA requests */
+#define D_R_PEND 0x00000400 /* no reset/flush allowed! */
+#define D_BYTEADDR 0x00001800 /* next byte to be accessed by esp */
+#define D_EN_CNT 0x00002000 /* enable byte counter */
+#define D_TC 0x00004000 /* terminal count */
+#define D_ILLAC 0x00008000 /* enable lance ethernet */
+#define D_DSBL_CSR_DRN 0x00010000 /* disable fifo drain on csr */
+#define D_DSBL_SCSI_DRN 0x00020000 /* disable fifo drain on reg */
+#define D_BURST_SIZE 0x000c0000 /* sbus read/write burst size */
+#define D_DIAG 0x00100000 /* disable fifo drain on addr */
+#define D_TWO_CYCLE 0x00200000 /* 2 clocks per transfer */
+#define D_FASTER 0x00400000 /* 3 clocks per transfer */
+#define D_TCI_DIS 0x00800000 /* disable intr on D_TC */
+#define D_EN_NEXT 0x01000000 /* enable auto next address */
+#define D_DMA_ON 0x02000000 /* enable dma from scsi */
+#define D_A_LOADED 0x04000000 /* address loaded */
+#define D_NA_LOADED 0x08000000 /* next address loaded */
+#define D_DEV_ID 0xf0000000 /* device ID */
+#define DMAREV_4300 0x00000000 /* Sunray DMA */
+#define DMAREV_ESC1 0x40000000 /* ESC gate array */
+#define DMAREV_1 0x80000000 /* 'DMA' */
+#define DMAREV_PLUS 0x90000000 /* 'DMA+' */
+#define DMAREV_2 0xa0000000 /* 'DMA2' */
+
+ volatile caddr_t addr;
+#define DMA_D_ADDR 0x01 /* DMA ADDR */
- volatile caddr_t addr;
-#define DMA_D_ADDR 0x01 /* DMA ADDR (in u_longs) */
+ /*
+ * some versions of dma controller lack the following
+ * two registers -- do not use them!
+ */
- volatile u_long bcnt; /* DMA COUNT (in u_longs) */
-#define D_BCNT_MASK 0x00ffffff /* only 24 bits */
+ volatile u_long bcnt; /* DMA COUNT */
+#define D_BCNT_MASK 0x00ffffff /* only 24 bits */
- volatile u_long test; /* DMA TEST (in u_longs) */
+ volatile u_long test; /* DMA TEST (in u_longs) */
};
diff --git a/sys/arch/sparc/dev/dmavar.h b/sys/arch/sparc/dev/dmavar.h
index e921d6b2fcd..c5ebb58357c 100644
--- a/sys/arch/sparc/dev/dmavar.h
+++ b/sys/arch/sparc/dev/dmavar.h
@@ -1,7 +1,10 @@
/* $NetBSD: dmavar.h,v 1.4 1994/11/27 00:08:34 deraadt Exp $ */
/*
- * Copyright (c) 1994 Peter Galbavy. All rights reserved.
+ * Copyright (c) 1994 Peter Galbavy
+ * Copyright (c) 1995 Theo de Raadt
+ * All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -12,7 +15,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by Peter Galbavy.
+ * This product includes software developed by Peter Galbavy and
+ * Theo de Raadt.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -29,42 +33,49 @@
*/
struct dma_softc {
- struct device sc_dev; /* us as a device */
- struct sbusdev sc_sd; /* sbus device */
- struct esp_softc *sc_esp; /* my scsi */
- struct dma_regs *sc_regs; /* the registers */
+ struct device sc_dev; /* us as a device */
+ struct sbusdev sc_sd; /* sbus device */
+ struct esp_softc *sc_esp; /* my scsi */
+ struct dma_regs *sc_regs; /* the registers */
int sc_active; /* DMA active ? */
int sc_rev; /* revision */
int sc_node; /* PROM node ID */
- size_t sc_dmasize;
- caddr_t *sc_dmaaddr;
+
+ size_t sc_segsize; /* current operation */
+ void **sc_dmaaddr;
size_t *sc_dmalen;
- void (*reset)(struct dma_softc *); /* reset routine */
- void (*enintr)(struct dma_softc *); /* enable interrupts */
- void (*start)(struct dma_softc *, caddr_t *, size_t *, int);
- int (*isintr)(struct dma_softc *); /* intrerrupt ? */
- int (*intr)(struct dma_softc *); /* intrerrupt ! */
+ char sc_dmapolling; /* ... is polled */
+ char sc_dmadev2mem; /* transfer direction */
};
-/*
- * We are not allowed to touch the DMA "flush" and "drain" bits
- * while it is still thinking about a request (DMA_RP).
- */
+void dmareset __P((struct dma_softc *sc));
+void dmastart __P((struct dma_softc *sc, void *addr,
+ size_t *len, int datain, int poll));
+int dmaintr __P((struct dma_softc *sc, int restart));
+int dmapending __P((struct dma_softc *sc));
+void dmadrain __P((struct dma_softc *sc));
+void dmaenintr __P((struct dma_softc *sc));
+int dmadisintr __P((struct dma_softc *sc));
-/*
- * TIME WAIT (to debug hanging machine problem)
- */
+#define DMACSR(sc) (sc->sc_regs->csr)
+#define DMADDR(sc) (sc->sc_regs->addr)
+#define DMABCNT(sc) (sc->sc_regs->bcnt)
-#define TIME_WAIT(COND, MSG, SC) { int count = 500000; \
- while (--count > 0 && (COND)) DELAY(1); \
- if (count == 0) { \
- printf("CSR = %x\n", SC->sc_regs->csr);\
- panic(MSG); } \
- }
+#define TIME_WAIT(cond, msg, sc) { \
+ int count = 500000; \
+ while (--count > 0 && (cond)) \
+ DELAY(1); \
+ if (count == 0) { \
+ printf("CSR = %x\n", (sc)->sc_regs->csr); \
+ panic(msg); \
+ } \
+}
-#define DMAWAIT(sc) TIME_WAIT((sc->sc_regs->csr & D_R_PEND), "DMAWAIT", sc)
-#define DMAWAIT1(sc) TIME_WAIT((sc->sc_regs->csr & D_DRAINING), "DMAWAIT1", sc)
-#define DMAREADY(sc) TIME_WAIT((!(sc->sc_regs->csr & D_DMA_ON)), "DMAREADY", sc)
+#define DMAWAIT_PEND(sc) \
+ TIME_WAIT((DMACSR(sc) & D_R_PEND), \
+ "DMAWAIT_PEND", sc)
-#define DMACSR(sc) (sc->sc_regs->csr)
-#define DMADDR(sc) (sc->sc_regs->addr)
+/* keep punching the chip until it's flushed */
+#define DMAWAIT_DRAIN(sc) \
+ TIME_WAIT((DMACSR(sc) |= D_DRAIN, DMACSR(sc) & D_DRAINING), \
+ "DMAWAIT_DRAIN", sc)
diff --git a/sys/arch/sparc/dev/esp.c b/sys/arch/sparc/dev/esp.c
index 85e456471f3..0ef0265291a 100644
--- a/sys/arch/sparc/dev/esp.c
+++ b/sys/arch/sparc/dev/esp.c
@@ -1,7 +1,13 @@
-/* $NetBSD: esp.c,v 1.26 1995/09/14 20:38:53 pk Exp $ */
+/*
+ * FOR NOW, YOU MAY NOT USE THIS DRIVER WITHOUT EXPLICITLY GRANTED
+ * PERMISSION.
+ */
+
+
+/* $NetBSD: esp.c,v 1.18 1995/02/01 12:37:24 pk Exp $ */
/*
- * Copyright (c) 1994 Peter Galbavy
+ * Copyright (c) 1995 Theo de Raadt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,7 +20,7 @@
* 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 Peter Galbavy
+ * This product includes software developed by Theo de Raadt.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -32,11 +38,14 @@
*/
/*
- * Based on aic6360 by Jarle Greipsland
- *
- * Acknowledgements: Many of the algorithms used in this driver are
- * inspired by the work of Julian Elischer (julian@tfs.com) and
- * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million!
+ * Based IN PART on aic6360 by Jarle Greipsland, an older esp driver
+ * by Peter Galbavy, and work by Charles Hannum on a few other drivers.
+ */
+
+/*
+ * todo:
+ * fix & enable sync
+ * confirm parity and bus failures do not lock up driver
*/
#include <sys/types.h>
@@ -53,181 +62,68 @@
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
+#include <scsi/scsi_message.h>
#include <machine/cpu.h>
#include <machine/autoconf.h>
#include <sparc/dev/sbusvar.h>
-#include <sparc/dev/dmareg.h>
#include <sparc/dev/dmavar.h>
+#include <sparc/dev/dmareg.h>
#include <sparc/dev/espreg.h>
#include <sparc/dev/espvar.h>
-int esp_debug = 0; /*ESP_SHOWPHASE|ESP_SHOWMISC|ESP_SHOWTRAC|ESP_SHOWCMDS;*/
-
-/*static*/ void espattach __P((struct device *, struct device *, void *));
-/*static*/ int espmatch __P((struct device *, void *, void *));
-/*static*/ int espprint __P((void *, char *));
-/*static*/ u_int esp_adapter_info __P((struct esp_softc *));
-/*static*/ void espreadregs __P((struct esp_softc *));
-/*static*/ int espgetbyte __P((struct esp_softc *, u_char *));
-/*static*/ void espselect __P((struct esp_softc *,
- u_char, u_char, caddr_t, u_char));
-/*static*/ void esp_scsi_reset __P((struct esp_softc *));
-/*static*/ void esp_reset __P((struct esp_softc *));
-/*static*/ void esp_init __P((struct esp_softc *, int));
-/*static*/ int esp_scsi_cmd __P((struct scsi_xfer *));
-/*static*/ int esp_poll __P((struct esp_softc *, struct ecb *));
-/*static*/ int espphase __P((struct esp_softc *));
-/*static*/ void esp_sched __P((struct esp_softc *));
-/*static*/ void esp_done __P((struct ecb *));
-/*static*/ void esp_msgin __P((struct esp_softc *));
-/*static*/ void esp_msgout __P((struct esp_softc *));
-/*static*/ int espintr __P((struct esp_softc *));
-/*static*/ void esp_timeout __P((void *arg));
-
-/* Linkup to the rest of the kernel */
+int esp_debug = ESP_SHOWPHASE|ESP_SHOWMISC|ESP_SHOWTRAC|ESP_SHOWCMDS; /**/
+
+#if 1
+#define ESPD(x)
+#else
+#define ESPD(x) printf x
+#endif
+
+void espattach __P((struct device *, struct device *, void *));
+int espmatch __P((struct device *, void *, void *));
+u_int esp_minphys __P((struct buf *));
+int espprint __P((void *, char *));
+void espreadregs __P((struct esp_softc *));
+int espgetbyte __P((struct esp_softc *, int));
+void espselect __P((struct esp_softc *));
+void esp_reset __P((struct esp_softc *));
+void esp_init __P((struct esp_softc *, int));
+int esp_scsi_cmd __P((struct scsi_xfer *));
+int esp_poll __P((struct esp_softc *, struct ecb *));
+int espphase __P((struct esp_softc *));
+void esp_sched __P((struct esp_softc *));
+void esp_done __P((struct ecb *));
+void esp_msgin __P((struct esp_softc *));
+void esp_makemsg __P((struct esp_softc *));
+void esp_msgout __P((struct esp_softc *));
+int espintr __P((struct esp_softc *));
+void esp_timeout __P((void *arg));
+
struct cfdriver espcd = {
- NULL, "esp", espmatch, espattach,
- DV_DULL, sizeof(struct esp_softc)
+ NULL, "esp", espmatch, espattach, DV_DULL, sizeof(struct esp_softc)
};
struct scsi_adapter esp_switch = {
- esp_scsi_cmd,
- minphys, /* no max at this level; handled by DMA code */
- NULL,
- NULL,
+ esp_scsi_cmd, esp_minphys, NULL, NULL
};
struct scsi_device esp_dev = {
- NULL, /* Use default error handler */
- NULL, /* have a queue, served by this */
- NULL, /* have no async handler */
- NULL, /* Use default 'done' routine */
+ NULL, NULL, NULL, NULL
};
/*
- * Read the ESP registers, and save their contents for later use.
- * ESP_STAT, ESP_STEP & ESP_INTR are mostly zeroed out when reading
- * ESP_INTR - so make sure it is the last read.
- *
- * I think that (from reading the docs) most bits in these registers
- * only make sense when he DMA CSR has an interrupt showing. So I have
- * coded this to not do anything if there is no interrupt or error
- * pending.
+ * Does anyone actually use this, and what for ?
*/
-void
-espreadregs(sc)
- struct esp_softc *sc;
-{
- volatile caddr_t esp = sc->sc_reg;
-
- /* they mean nothing if the is no pending interrupt ??? */
- if (!(DMA_ISINTR(sc->sc_dma)))
- return;
-
- /* Only the stepo bits are of interest */
- sc->sc_espstep = esp[ESP_STEP] & ESPSTEP_MASK;
- sc->sc_espstat = esp[ESP_STAT];
- sc->sc_espintr = esp[ESP_INTR];
-
- ESP_MISC(("regs[intr=%02x,stat=%02x,step=%02x] ", sc->sc_espintr,
- sc->sc_espstat, sc->sc_espstep));
-}
-
-/*
- * no error checking ouch
- */
-int
-espgetbyte(sc, v)
- struct esp_softc *sc;
- u_char *v;
-{
- volatile caddr_t esp = sc->sc_reg;
-
- if (!(esp[ESP_FFLAG] & ESPFIFO_FF)) {
-ESPCMD(sc, ESPCMD_FLUSH);
-DELAY(1);
- ESPCMD(sc, ESPCMD_TRANS);
- while (!DMA_ISINTR(sc->sc_dma))
- DELAY(1);
- /*
- * If we read something, then clear the outstanding
- * interrupts
- */
- espreadregs(sc);
- if (sc->sc_espintr & ESPINTR_ILL) /* Oh, why? */
- return -1;
- }
- if (!(esp[ESP_FFLAG] & ESPFIFO_FF)) {
- printf("error... ");
- return -1;
- }
- *v = esp[ESP_FIFO];
- return 0;
-}
-
-/*
- * Send a command to a target, set the driver state to ESP_SELECTING
- * and let the caller take care of the rest.
- *
- * Keeping this as a function allows me to say that this may be done
- * by DMA instead of programmed I/O soon.
- */
-void
-espselect(sc, target, lun, cmd, clen)
- struct esp_softc *sc;
- u_char target, lun;
- caddr_t cmd;
- u_char clen;
-{
- volatile caddr_t esp = sc->sc_reg;
- int i;
-
- /*
- * The docs say the target register is never reset, and I
- * can't think of a better place to set it
- */
- esp[ESP_SELID] = target;
- esp[ESP_SYNCOFF] = sc->sc_tinfo[target].offset;
- esp[ESP_SYNCTP] = 250 / sc->sc_tinfo[target].period;
-
- /*
- * Who am I. This is where we tell the target that we are
- * happy for it to disconnect etc.
- */
-#if 1
- if ((sc->sc_tinfo[target].flags & T_XXX) == 0)
-#endif
- esp[ESP_FIFO] = ESP_MSG_IDENTIFY(lun);
-
- /* Now the command into the FIFO */
- for (i = 0; i < clen; i++)
- esp[ESP_FIFO] = *cmd++;
-
- /* And get the targets attention */
-#if 1
- if ((sc->sc_tinfo[target].flags & T_XXX) == 0)
-#endif
- ESPCMD(sc, ESPCMD_SELATN);
-#if 1
- else
- ESPCMD(sc, ESPCMD_SELNATN);
-#endif
-
- /* new state ESP_SELECTING */
- sc->sc_state = ESP_SELECTING;
-}
-
int
espprint(aux, name)
void *aux;
char *name;
{
- if (name != NULL)
- printf("%s: scsibus ", name);
- return UNCONF;
+ return (UNCONF);
}
+
int
espmatch(parent, vcf, aux)
struct device *parent;
@@ -245,6 +141,7 @@ espmatch(parent, vcf, aux)
return (probeget(ra->ra_vaddr, 1) != -1);
}
+
/*
* Attach this instance, and then all the sub-devices
*/
@@ -255,7 +152,9 @@ espattach(parent, self, aux)
{
register struct confargs *ca = aux;
struct esp_softc *sc = (void *)self;
+ struct espregs *espr;
struct bootpath *bp;
+ int freq;
/*
* Make sure things are sane. I don't know if this is ever
@@ -274,11 +173,13 @@ espattach(parent, self, aux)
* address space.
*/
if (ca->ca_ra.ra_vaddr)
- sc->sc_reg = (volatile caddr_t) ca->ca_ra.ra_vaddr;
+ sc->sc_regs = (struct espregs *) ca->ca_ra.ra_vaddr;
else {
- sc->sc_reg = (volatile caddr_t)
- mapiodev(ca->ca_ra.ra_paddr, ca->ca_ra.ra_len, ca->ca_bustype);
+ sc->sc_regs = (struct espregs *)
+ mapiodev(ca->ca_ra.ra_paddr, ca->ca_ra.ra_len,
+ ca->ca_bustype);
}
+ espr = sc->sc_regs;
/* Other settings */
sc->sc_node = ca->ca_ra.ra_node;
@@ -293,85 +194,66 @@ espattach(parent, self, aux)
sc->sc_freq = ((struct sbus_softc *)
sc->sc_dev.dv_parent)->sc_clockfreq;
- /* gimme Mhz */
- sc->sc_freq /= 1000000;
+ freq = sc->sc_freq / 1000000; /* gimme Mhz */
/*
- * This is the value used to start sync negotiations
- * For a 25Mhz clock, this gives us 40, or 160nS, or
- * 6.25Mb/s. It is constant for each adapter.
- *
- * In turn, notice that the ESP register "SYNCTP" is
- * = (250 / the negotiated period). It works, try it
- * on paper.
+ * This is the value used to start sync negotiations. For a
+ * 25Mhz clock, this gives us 40, or 160nS, or 6.25Mb/s. It
+ * is constant for each adapter. In turn, notice that the ESP
+ * register "SYNCTP" is = (250 / the negotiated period).
*/
- sc->sc_minsync = 1000 / sc->sc_freq;
+ sc->sc_minsync = 1000 / freq;
/* 0 is actually 8, even though the register only has 3 bits */
- sc->sc_ccf = FREQTOCCF(sc->sc_freq) & 0x07;
+ sc->sc_ccf = FREQTOCCF(freq) & 0x07;
- /* The value *must not* be == 1. Make it 2 */
+ /* The value must not be 1 -- make it 2 */
if (sc->sc_ccf == 1)
sc->sc_ccf = 2;
/*
- * The recommended timeout is 250ms. This register is loaded
- * with a value calculated as follows, from the docs:
+ * The recommended timeout is 250ms (1/4 seconds). This
+ * register is loaded with a value calculated as follows:
*
* (timout period) x (CLK frequency)
* reg = -------------------------------------
* 8192 x (Clock Conversion Factor)
*
- * We have the CCF from above, so the sum is simple, and generally
- * gives us a constant of 153. Try working out a few and see.
+ * We have the CCF from above. For a 25MHz clock this gives
+ * a constant of 153 (we round up).
*/
- sc->sc_timeout = ESP_DEF_TIMEOUT;
+ sc->sc_timeout = (sc->sc_freq / 4 / 8192 / sc->sc_ccf) + 1;
/*
- * find the DMA by poking around the dma device structures
- *
- * What happens here is that if the dma driver has not been
- * configured, then this returns a NULL pointer. Then when the
- * dma actually gets configured, it does the opposing test, and
- * if the sc->sc_esp field in it's softc is NULL, then tries to
- * find the matching esp driver.
- *
+ * find the corresponding DMA controller.
*/
sc->sc_dma = ((struct dma_softc *)getdevunit("dma",
sc->sc_dev.dv_unit));
-
- /*
- * and a back pointer to us, for DMA
- */
if (sc->sc_dma)
sc->sc_dma->sc_esp = sc;
- /*
- * It is necessary to try to load the 2nd config register here,
- * to find out what rev the esp chip is, else the esp_reset
- * will not set up the defaults correctly.
- */
sc->sc_cfg1 = sc->sc_id | ESPCFG1_PARENB;
- sc->sc_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_RPE;
- sc->sc_cfg3 = ESPCFG3_CDB;
- sc->sc_reg[ESP_CFG2] = sc->sc_cfg2;
+ sc->sc_cfg2 = 0;
+ sc->sc_cfg3 = 0;
- if ((sc->sc_reg[ESP_CFG2] & ~ESPCFG2_RSVD) != (ESPCFG2_SCSI2 | ESPCFG2_RPE)) {
+ /*
+ * The ESP100 only has a cfg1 register. The ESP100A has it, but
+ * lacks the cfg3 register. Thus, we can tell which chip we have.
+ * XXX: what about the FAS100A?
+ */
+ espr->espr_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_RPE;
+ if ((espr->espr_cfg2 & ~ESPCFG2_RSVD) != (ESPCFG2_SCSI2 | ESPCFG2_RPE)) {
printf(": ESP100");
sc->sc_rev = ESP100;
} else {
- sc->sc_cfg2 = 0;
- sc->sc_reg[ESP_CFG2] = sc->sc_cfg2;
- sc->sc_cfg3 = 0;
- sc->sc_reg[ESP_CFG3] = sc->sc_cfg3;
- sc->sc_cfg3 = 5;
- sc->sc_reg[ESP_CFG3] = sc->sc_cfg3;
- if (sc->sc_reg[ESP_CFG3] != 5) {
+ espr->espr_cfg2 = 0;
+ espr->espr_cfg3 = 0;
+ espr->espr_cfg3 = ESPCFG3_CDB | ESPCFG3_FCLK;
+ if (espr->espr_cfg3 != (ESPCFG3_CDB | ESPCFG3_FCLK)) {
printf(": ESP100A");
sc->sc_rev = ESP100A;
} else {
- sc->sc_cfg3 = 0;
- sc->sc_reg[ESP_CFG3] = sc->sc_cfg3;
+ espr->espr_cfg3 = 0;
printf(": ESP200");
sc->sc_rev = ESP200;
}
@@ -380,16 +262,23 @@ espattach(parent, self, aux)
sc->sc_state = 0;
esp_init(sc, 1);
- printf(" %dMhz, target %d\n", sc->sc_freq, sc->sc_id);
+ printf(" %dMhz, target %d\n", freq, sc->sc_id);
- /* add me to the sbus structures */
- sc->sc_sd.sd_reset = (void *) esp_reset;
#if defined(SUN4C) || defined(SUN4M)
- if (ca->ca_bustype == BUS_SBUS)
+ if (ca->ca_bustype == BUS_SBUS) {
+ /* add to the sbus structures */
+ sc->sc_sd.sd_reset = (void *) esp_reset;
sbus_establish(&sc->sc_sd, &sc->sc_dev);
+
+ /*
+ * If the device is in an SBUS slave slot, bail now.
+ */
+ if (sbus_slavecheck(self, ca))
+ return;
+ }
#endif /* SUN4C || SUN4M */
- /* and the interuppts */
+ /* and the interupts */
sc->sc_ih.ih_fun = (void *) espintr;
sc->sc_ih.ih_arg = sc;
intr_establish(sc->sc_pri, &sc->sc_ih);
@@ -405,21 +294,23 @@ espattach(parent, self, aux)
sc->sc_link.openings = 2;
/*
- * If the boot path is "esp" at the moment and it's me, then
- * walk our pointer to the sub-device, ready for the config
- * below.
+ * If the boot path is "esp", and the numbers point to
+ * this controller, then advance the bootpath a step.
+ * XXX boot /sbus/esp/sd@3,0 passes in esp@0,0 -- which
+ * is almost always wrong, but match in that case anyways.
*/
bp = ca->ca_ra.ra_bp;
+ bootcomp = NULL;
switch (ca->ca_bustype) {
case BUS_SBUS:
if (bp != NULL && strcmp(bp->name, "esp") == 0 &&
- SAME_ESP(sc, bp, ca))
- bootpath_store(1, bp + 1);
+ ((bp->val[0]==ca->ca_slot &&
+ (bp->val[1]==ca->ca_offset || bp->val[1]==0)) ||
+ (bp->val[0]==-1 && bp->val[1]==sc->sc_dev.dv_unit)))
+ bootcomp = sc->sc_bp = bp + 1;
break;
default:
- if (bp != NULL && strcmp(bp->name, "esp") == 0 &&
- bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit)
- bootpath_store(1, bp + 1);
+ bootcomp = sc->sc_bp = bp;
break;
}
@@ -427,66 +318,184 @@ espattach(parent, self, aux)
* Now try to attach all the sub-devices
*/
config_found(self, &sc->sc_link, espprint);
+}
- bootpath_store(1, NULL);
+
+/*
+ * Warning: This inserts two commands into the ESP command fifo. Because
+ * there are only 2 entries in that fifo, you may need to put a DELAY(1)
+ * after calling this, if you are going to issue another command soon.
+ */
+void
+espflush(sc)
+ struct esp_softc *sc;
+{
+ struct espregs *espr = sc->sc_regs;
+
+ if (espr->espr_fflag & ESPFIFO_FF) {
+ espr->espr_cmd = ESPCMD_FLUSH;
+ espr->espr_cmd = ESPCMD_NOP;
+ }
}
/*
- * This is the generic esp reset function. It does not reset the SCSI bus,
- * only this controllers, but kills any on-going commands, and also stops
- * and resets the DMA.
+ * Read the ESP registers, and save their contents for later use.
+ * ESP_STAT, ESP_STEP & ESP_INTR are mostly zeroed out when reading
+ * ESP_INTR - so make sure it is the last read.
*
- * After reset, registers are loaded with the defaults from the attach
- * routine above.
+ * XXX: TDR: this logic seems unsound
+ * I think that (from reading the docs) most bits in these registers
+ * only make sense when the DMA CSR has an interrupt showing. So I have
+ * coded this to not do anything if there is no interrupt or error
+ * pending.
+ */
+void
+espreadregs(sc)
+ struct esp_softc *sc;
+{
+ struct espregs *espr = sc->sc_regs;
+
+ /* they mean nothing if the is no pending interrupt ??? */
+ if (!(dmapending(sc->sc_dma)))
+ return;
+
+ /* Only the stepo bits are of interest */
+ sc->sc_espstep = espr->espr_step & ESPSTEP_MASK;
+ sc->sc_espstat = espr->espr_stat;
+ sc->sc_espintr = espr->espr_intr;
+
+ ESP_MISC(("regs[intr=%02x,stat=%02x,step=%02x] ", sc->sc_espintr,
+ sc->sc_espstat, sc->sc_espstep));
+}
+
+/*
+ * returns -1 if no byte is available because fifo is empty.
+ */
+int
+espgetbyte(sc, dotrans)
+ struct esp_softc *sc;
+ int dotrans;
+{
+ struct espregs *espr = sc->sc_regs;
+
+ if (espr->espr_fflag & ESPFIFO_FF)
+ return espr->espr_fifo;
+ return -1;
+}
+
+/*
+ * Send a command to a target, as well as any required messages.
+ * There are three cases. The first two cases are fairly simple..
+ * 1) command alone
+ * load command into fifo, and use ESPCMD_SELNATN
+ * 2) MSG_IDENTIFY + command
+ * load message and command into fifo, and use ESPCMD_SELATN
+ * 3) a bunch of messages + command
+ * load first message byte into fifo. Use ESPCMD_SELATNS. When the
+ * next interrupt occurs, load the remainer of the message into
+ * the fifo and use ESPCMD_TRANS. When the device is ready to
+ * receive the command, it will switch into COMMAND_PHASE, and
+ * at that point we will feed it the command.
+ */
+void
+espselect(sc)
+ struct esp_softc *sc;
+{
+ struct espregs *espr = sc->sc_regs;
+ register struct ecb *ecb = sc->sc_nexus;
+ register struct scsi_link *sc_link = ecb->xs->sc_link;
+ struct esp_tinfo *ti = &sc->sc_tinfo[sc_link->target];
+ u_char *cmd = (u_char *)&ecb->cmd;
+ int loadcmd = 1;
+ int outcmd, i;
+
+ espr->espr_selid = sc_link->target;
+ espr->espr_syncoff = ti->offset;
+ espr->espr_synctp = ti->synctp;
+
+ sc->sc_state = ESPS_SELECTING;
+
+ if (ecb->xs->flags & SCSI_RESET)
+ sc->sc_msgpriq = SEND_DEV_RESET;
+ else if (ti->flags & DO_NEGOTIATE)
+ sc->sc_msgpriq = SEND_SDTR;
+ else
+ sc->sc_msgpriq = SEND_IDENTIFY;
+
+ if (sc->sc_msgpriq) {
+ esp_makemsg(sc);
+
+ ESPD(("OM["));
+ for (i = 0; i < sc->sc_omlen; i++)
+ ESPD(("%02x%c", sc->sc_omp[i],
+ (i == sc->sc_omlen-1) ? ']' : ' '));
+ ESPD((" "));
+
+ espr->espr_fifo = sc->sc_omp[0]; /* 1st msg byte only */
+ if (sc->sc_omlen == 1) {
+ outcmd = ESPCMD_SELATN;
+ } else {
+ outcmd = ESPCMD_SELATNS;
+ /* and this will will load the rest of the msg bytes */
+ sc->sc_state = ESPS_SELECTSTOP;
+ loadcmd = 0;
+ }
+ } else
+ outcmd = ESPCMD_SELNATN;
+
+ ESPD(("P%d/%02x/%d ", (ecb->xs->flags & SCSI_POLL) ? 1 : 0, outcmd, loadcmd));
+
+ if (loadcmd) {
+ ESPD(("CMD["));
+ for (i = 0; i < ecb->clen; i++)
+ ESPD(("%02x%c", cmd[i],
+ (i == ecb->clen-1) ? ']' : ' '));
+ ESPD((" "));
+
+ /* load the command into the FIFO */
+ for (i = 0; i < ecb->clen; i++)
+ espr->espr_fifo = cmd[i];
+ }
+
+ espr->espr_cmd = outcmd;
+ if (!(ecb->xs->flags & SCSI_POLL))
+ sc->sc_flags |= ESPF_MAYDISCON;
+}
+
+
+/*
+ * Reset the ESP and DMA chips. Stops any transactions dead in the water;
+ * does not cause an interrupt.
*/
void
esp_reset(sc)
struct esp_softc *sc;
{
- volatile caddr_t esp = sc->sc_reg;
+ struct espregs *espr = sc->sc_regs;
- /* reset DMA first */
- DMA_RESET(sc->sc_dma);
+ dmareset(sc->sc_dma); /* reset DMA first */
- ESPCMD(sc, ESPCMD_RSTCHIP); /* reset chip */
- ESPCMD(sc, ESPCMD_NOP);
- DELAY(500);
+ espr->espr_cmd = ESPCMD_RSTCHIP;
+ DELAY(5);
+ espr->espr_cmd = ESPCMD_NOP;
+ DELAY(5);
/* do these backwards, and fall through */
switch (sc->sc_rev) {
case ESP200:
- esp[ESP_CFG3] = sc->sc_cfg3;
+ espr->espr_cfg3 = sc->sc_cfg3;
case ESP100A:
- esp[ESP_CFG2] = sc->sc_cfg2;
+ espr->espr_cfg2 = sc->sc_cfg2;
case ESP100:
- esp[ESP_CFG1] = sc->sc_cfg1;
- esp[ESP_CCF] = sc->sc_ccf;
- esp[ESP_SYNCOFF] = 0;
- esp[ESP_TIMEOUT] = sc->sc_timeout;
+ espr->espr_cfg1 = sc->sc_cfg1;
+ espr->espr_ccf = sc->sc_ccf;
+ espr->espr_syncoff = 0;
+ espr->espr_timeout = sc->sc_timeout;
break;
- default:
- printf("%s: unknown revision code, assuming ESP100\n",
- sc->sc_dev.dv_xname);
- esp[ESP_CFG1] = sc->sc_cfg1;
- esp[ESP_CCF] = sc->sc_ccf;
- esp[ESP_SYNCOFF] = 0;
- esp[ESP_TIMEOUT] = sc->sc_timeout;
}
}
/*
- * Reset the SCSI bus, but not the chip
- */
-void
-esp_scsi_reset(sc)
- struct esp_softc *sc;
-{
- printf("esp: resetting SCSI bus\n");
- ESPCMD(sc, ESPCMD_RSTSCSI);
- DELAY(50);
-}
-
-/*
* Initialize esp state machine
*/
void
@@ -494,8 +503,9 @@ esp_init(sc, doreset)
struct esp_softc *sc;
int doreset;
{
+ struct espregs *espr = sc->sc_regs;
struct ecb *ecb;
- int r;
+ int i;
/*
* reset the chip to a known state
@@ -503,8 +513,8 @@ esp_init(sc, doreset)
esp_reset(sc);
if (doreset) {
- ESPCMD(sc, ESPCMD_RSTSCSI);
- DELAY(50);
+ espr->espr_cmd = ESPCMD_RSTSCSI;
+ DELAY(500);
/* cheat: we don't want the state machine to reset again.. */
esp_reset(sc);
}
@@ -516,13 +526,13 @@ esp_init(sc, doreset)
sc->sc_nexus = 0;
ecb = sc->sc_ecb;
bzero(ecb, sizeof(sc->sc_ecb));
- for (r = 0; r < sizeof(sc->sc_ecb) / sizeof(*ecb); r++) {
+ for (i = 0; i < sizeof(sc->sc_ecb) / sizeof(*ecb); i++) {
TAILQ_INSERT_TAIL(&sc->free_list, ecb, chain);
ecb++;
}
bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
} else {
- sc->sc_state = ESP_IDLE;
+ sc->sc_state = ESPS_IDLE;
if (sc->sc_nexus != NULL) {
sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP;
untimeout(esp_timeout, sc->sc_nexus);
@@ -536,26 +546,20 @@ esp_init(sc, doreset)
}
}
- sc->sc_phase = sc->sc_prevphase = INVALID_PHASE;
- for (r = 0; r < 8; r++) {
- struct esp_tinfo *tp = &sc->sc_tinfo[r];
+ for (i = 0; i < 8; i++) {
+ struct esp_tinfo *ti = &sc->sc_tinfo[i];
- tp->flags = DO_NEGOTIATE | NEED_TO_RESET;
- tp->period = sc->sc_minsync;
- tp->offset = ESP_SYNC_REQ_ACK_OFS;
+ ti->flags = DO_NEGOTIATE;
+ ti->period = sc->sc_minsync;
+ ti->synctp = 250 / ti->period;
+ ti->offset = ESP_SYNC_REQOFF;
}
- sc->sc_state = ESP_IDLE;
- return;
+ sc->sc_state = ESPS_IDLE;
}
/*
- * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS
- */
-
-/*
- * Start a SCSI-command
- * This function is called by the higher level SCSI-driver to queue/run
- * SCSI-commands.
+ * Start a SCSI-command: This function is called by the higher level
+ * SCSI-driver to queue/run SCSI-commands.
*/
int
esp_scsi_cmd(xs)
@@ -563,14 +567,13 @@ esp_scsi_cmd(xs)
{
struct scsi_link *sc_link = xs->sc_link;
struct esp_softc *sc = sc_link->adapter_softc;
- struct ecb *ecb;
- int s, flags;
+ struct ecb *ecb;
+ int s;
- ESP_TRACE(("esp_scsi_cmd\n"));
- ESP_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen,
- sc_link->target));
+ /*ESPD(("NS%08x/%08x/%d ", xs, xs->data, xs->datalen));*/
- flags = xs->flags;
+ /* XXX: set lun */
+ xs->cmd->bytes[0] |= (sc_link->lun << SCSI_CMD_LUN_SHIFT);
/* Get a esp command block */
s = splbio();
@@ -582,7 +585,6 @@ esp_scsi_cmd(xs)
if (ecb == NULL) {
xs->error = XS_DRIVER_STUFFUP;
- ESP_MISC(("TRY_AGAIN_LATER"));
return TRY_AGAIN_LATER;
}
@@ -597,21 +599,30 @@ esp_scsi_cmd(xs)
s = splbio();
TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain);
- timeout(esp_timeout, ecb, (xs->timeout*hz)/1000);
+ if ((xs->flags & SCSI_POLL) == 0)
+ timeout(esp_timeout, ecb, (xs->timeout * hz) / 1000);
- if (sc->sc_state == ESP_IDLE)
+ if (sc->sc_state == ESPS_IDLE)
esp_sched(sc);
-
splx(s);
- if (flags & SCSI_POLL) {
- /* Not allowed to use interrupts, use polling instead */
+ /* Not allowed to use interrupts, use polling instead */
+ if (xs->flags & SCSI_POLL)
return esp_poll(sc, ecb);
- }
-
- ESP_MISC(("SUCCESSFULLY_QUEUED"));
return SUCCESSFULLY_QUEUED;
+}
+/*
+ * Adjust transfer size in buffer structure
+ *
+ * We have no max transfer size, since the DMA driver will break it
+ * down into watever is needed.
+ */
+u_int
+esp_minphys(bp)
+ struct buf *bp;
+{
+ return (minphys(bp));
}
/*
@@ -623,40 +634,37 @@ esp_poll(sc, ecb)
struct ecb *ecb;
{
struct scsi_xfer *xs = ecb->xs;
- int count = xs->timeout * 10;
+ int count = xs->timeout * 1000;
ESP_TRACE(("esp_poll\n"));
while (count) {
- if (DMA_ISINTR(sc->sc_dma)) {
- espintr(sc);
+ if (dmapending(sc->sc_dma)) {
+ /*
+ * We decrement the interrupt event counter to
+ * repair it... because this isn't a real interrupt.
+ */
+ if (espintr(sc))
+ --sc->sc_intrcnt.ev_count;
+ continue;
}
if (xs->flags & ITSDONE)
break;
- DELAY(5);
- if (sc->sc_state == ESP_IDLE) {
- ESP_TRACE(("esp_poll: rescheduling"));
- esp_sched(sc);
- }
+ DELAY(1);
count--;
}
if (count == 0) {
- ESP_MISC(("esp_poll: timeout"));
- esp_timeout((caddr_t)ecb);
+ ecb->xs->error = XS_TIMEOUT;
+ sc_print_addr(ecb->xs->sc_link);
+ printf("timed out\n");
+ esp_reset(sc);
}
-
+ dmaenintr(sc->sc_dma);
return COMPLETE;
}
/*
- * LOW LEVEL SCSI UTILITIES
- */
-
-/*
- * Determine the SCSI bus phase, return either a real SCSI bus phase
- * or some pseudo phase we use to detect certain exceptions.
- *
* Notice that we do not read the live register on an ESP100. On the
* ESP100A and above the FE (Feature Enable) bit in config 2 latches
* the phase in the register so it is safe to read.
@@ -665,13 +673,9 @@ int
espphase(sc)
struct esp_softc *sc;
{
-
- if (sc->sc_espintr & ESPINTR_DIS) /* Disconnected */
- return BUSFREE_PHASE;
if (sc->sc_rev > ESP100)
- return (sc->sc_reg[ESP_STAT] & ESPSTAT_PHASE);
-
+ return (sc->sc_regs->espr_stat & ESPSTAT_PHASE);
return (sc->sc_espstat & ESPSTAT_PHASE);
}
@@ -680,7 +684,7 @@ espphase(sc)
* Schedule a scsi operation. This has now been pulled out of the interrupt
* handler so that we may call it from esp_scsi_cmd and esp_done. This may
* save us an unecessary interrupt just to get things going. Should only be
- * called when state == ESP_IDLE and at bio pl.
+ * called when state == ESPS_IDLE and at bio pl.
*/
void
esp_sched(sc)
@@ -701,14 +705,13 @@ esp_sched(sc)
sc_link = ecb->xs->sc_link;
t = sc_link->target;
if (!(sc->sc_tinfo[t].lubusy & (1 << sc_link->lun))) {
- struct esp_tinfo *ti = &sc->sc_tinfo[t];
+ struct esp_tinfo *ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
TAILQ_REMOVE(&sc->ready_list, ecb, chain);
sc->sc_nexus = ecb;
sc->sc_flags = 0;
- sc->sc_prevphase = INVALID_PHASE;
sc_link = ecb->xs->sc_link;
- espselect(sc, t, sc_link->lun, cmd, ecb->clen);
+ espselect(sc);
ti = &sc->sc_tinfo[sc_link->target];
sc->sc_dp = ecb->daddr;
sc->sc_dleft = ecb->dleft;
@@ -740,9 +743,13 @@ esp_done(ecb)
* commands for this target/lunit, else we lose the sense info.
* We don't support chk sense conditions for the request sense cmd.
*/
- if (xs->error == XS_NOERROR && !(ecb->flags & ECB_CHKSENSE)) {
- if ((ecb->stat & ST_MASK)==SCSI_CHECK) {
+ if (xs->error == XS_NOERROR) {
+ if (ecb->flags & ECB_CHKSENSE)
+ xs->error = XS_SENSE;
+ else if ((ecb->stat & ST_MASK) == SCSI_CHECK) {
struct scsi_sense *ss = (void *)&ecb->cmd;
+
+ ESPD(("RS "));
ESP_MISC(("requesting sense "));
/* First, save the return values */
xs->resid = ecb->dleft;
@@ -750,7 +757,7 @@ esp_done(ecb)
/* Next, setup a request sense command block */
bzero(ss, sizeof(*ss));
ss->opcode = REQUEST_SENSE;
- ss->byte2 = sc_link->lun << 5;
+ ss->byte2 = sc_link->lun << SCSI_CMD_LUN_SHIFT;
ss->length = sizeof(struct scsi_sense_data);
ecb->clen = sizeof(*ss);
ecb->daddr = (char *)&xs->sense;
@@ -761,29 +768,24 @@ esp_done(ecb)
~(1<<sc_link->lun);
sc->sc_tinfo[sc_link->target].senses++;
/* found it */
- if (sc->sc_nexus == ecb) {
- sc->sc_nexus = NULL;
- sc->sc_state = ESP_IDLE;
- esp_sched(sc);
- }
+ if (sc->sc_nexus != ecb)
+ TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
+ sc->sc_state = ESPS_IDLE;
+ esp_sched(sc);
return;
- }
- }
-
- if (xs->error == XS_NOERROR && (ecb->flags & ECB_CHKSENSE)) {
- xs->error = XS_SENSE;
- } else {
- xs->resid = ecb->dleft;
+ } else
+ xs->resid = ecb->dleft;
}
+
xs->flags |= ITSDONE;
-#ifdef ESP_DEBUG
+#if ESP_DEBUG > 1
if (esp_debug & ESP_SHOWMISC) {
- printf("err=0x%02x ",xs->error);
+ printf("err=0x%02x ", xs->error);
if (xs->error == XS_SENSE)
- printf("sense=%2x\n", xs->sense.error_code);
+ printf("sense=%02x\n", xs->sense.error_code);
}
- if ((xs->resid || xs->error > XS_SENSE) && esp_debug & ESP_SHOWMISC) {
+ if ((xs->resid || xs->error > XS_SENSE) && (esp_debug & ESP_SHOWMISC)) {
if (xs->resid)
printf("esp_done: resid=%d\n", xs->resid);
if (xs->error)
@@ -799,24 +801,24 @@ esp_done(ecb)
* longer busy. This code is sickening, but it works.
*/
if (ecb == sc->sc_nexus) {
- sc->sc_state = ESP_IDLE;
sc->sc_tinfo[sc_link->target].lubusy &= ~(1<<sc_link->lun);
+ sc->sc_nexus = NULL;
+ sc->sc_state = ESPS_IDLE;
esp_sched(sc);
} else if (sc->ready_list.tqh_last == &ecb->chain.tqe_next) {
TAILQ_REMOVE(&sc->ready_list, ecb, chain);
} else {
register struct ecb *ecb2;
+
for (ecb2 = sc->nexus_list.tqh_first; ecb2;
ecb2 = ecb2->chain.tqe_next)
- if (ecb2 == ecb) {
- TAILQ_REMOVE(&sc->nexus_list, ecb, chain);
- sc->sc_tinfo[sc_link->target].lubusy
- &= ~(1<<sc_link->lun);
+ if (ecb2 == ecb)
break;
- }
- if (ecb2)
- ;
- else if (ecb->chain.tqe_next) {
+ if (ecb2) {
+ TAILQ_REMOVE(&sc->nexus_list, ecb, chain);
+ sc->sc_tinfo[sc_link->target].lubusy &=
+ ~(1<<sc_link->lun);
+ } else if (ecb->chain.tqe_next) {
TAILQ_REMOVE(&sc->ready_list, ecb, chain);
} else {
printf("%s: can't find matching ecb\n",
@@ -829,8 +831,8 @@ esp_done(ecb)
TAILQ_INSERT_HEAD(&sc->free_list, ecb, chain);
sc->sc_tinfo[sc_link->target].cmds++;
+ ESPD(("DONE%d ", xs->resid));
scsi_done(xs);
- return;
}
/*
@@ -843,13 +845,13 @@ esp_done(ecb)
* else there will be an illegal command interrupt.
*/
#define esp_sched_msgout(m) \
- do { \
- ESP_MISC(("esp_sched_msgout %d ", m)); \
- ESPCMD(sc, ESPCMD_SETATN); \
- sc->sc_msgpriq |= (m); \
+ do { \
+ sc->sc_regs->espr_cmd = ESPCMD_SETATN; \
+ sc->sc_msgpriq |= (m); \
+ ESPD(("Mq%02x ", sc->sc_msgpriq)); \
} while (0)
-#define IS1BYTEMSG(m) (((m) != 1 && (m) < 0x20) || (m) & 0x80)
+#define IS1BYTEMSG(m) (((m) != 1 && ((unsigned)(m)) < 0x20) || (m) & 0x80)
#define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20)
#define ISEXTMSG(m) ((m) == 1)
@@ -863,8 +865,10 @@ void
esp_msgin(sc)
register struct esp_softc *sc;
{
- volatile caddr_t esp = sc->sc_reg;
+ struct espregs *espr = sc->sc_regs;
+ struct ecb *ecb;
int extlen;
+ int x, i;
ESP_TRACE(("esp_msgin "));
@@ -874,6 +878,9 @@ esp_msgin(sc)
return;
}
+ ESPD(("MSGIN:%d ", espr->espr_fflag & ESPFIFO_FF));
+
+#ifdef fixme
/*
* Prepare for a new message. A message should (according
* to the SCSI standard) be transmitted in one single
@@ -881,166 +888,191 @@ esp_msgin(sc)
* then this is a new message.
*/
if (sc->sc_prevphase != MESSAGE_IN_PHASE) {
- sc->sc_flags &= ~ESP_DROP_MSGI;
+ sc->sc_flags &= ~ESPF_DROP_MSGI;
+ if (sc->sc_imlen > 0) {
+ printf("%s: message type %02x",
+ sc->sc_dev.dv_xname, sc->sc_imess[0]);
+ if (!IS1BYTEMSG(sc->sc_imess[0]))
+ printf(" %02x", sc->sc_imess[1]);
+ printf(" was dropped\n");
+ }
sc->sc_imlen = 0;
}
+#endif
- if (sc->sc_state == ESP_RESELECTED && sc->sc_imlen == 0) {
- /*
- * Which target is reselecting us? (The ID bit really)
- */
- (void)espgetbyte(sc, &sc->sc_selid);
- sc->sc_selid &= ~(1<<sc->sc_id);
- ESP_MISC(("selid=0x%2x ", sc->sc_selid));
+ /*
+ * Which target is reselecting us? (The ID bit really)
+ * On a reselection, there should be the reselecting target's
+ * id and an identify message in the fifo.
+ */
+ if (sc->sc_state == ESPS_RESELECTED && sc->sc_imlen == 0) {
+ x = espgetbyte(sc, 0);
+ if (x == -1) {
+ printf("%s: msgin reselection found fifo empty\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ ESPD(("ID=%02x ", x));
+ sc->sc_selid = (u_char)x & ~(1<<sc->sc_id);
+ ESP_MISC(("selid=0x%02x ", sc->sc_selid));
}
- for (;;) {
- /*
- * If parity errors just dump everything on the floor
- */
- if (sc->sc_espstat & ESPSTAT_PE) {
- esp_sched_msgout(SEND_PARITY_ERROR);
- sc->sc_flags |= ESP_DROP_MSGI;
- }
+ /*
+ * If parity errors just dump everything on the floor
+ */
+ if (sc->sc_espstat & ESPSTAT_PE) {
+ printf("%s: SCSI bus parity error\n",
+ sc->sc_dev.dv_xname);
+ esp_sched_msgout(SEND_PARITY_ERROR);
+ DELAY(1);
+ sc->sc_flags |= ESPF_DROP_MSGI;
+ }
- /*
- * If we're going to reject the message, don't bother storing
- * the incoming bytes. But still, we need to ACK them.
- */
- if ((sc->sc_flags & ESP_DROP_MSGI) == 0) {
- if (espgetbyte(sc, &sc->sc_imess[sc->sc_imlen])) {
- /*
- * XXX - hack alert.
- * Apparently, the chip didn't grok a multibyte
- * message from the target; set a flag that
- * will cause selection w.o. ATN when we retry
- * (after a SCSI reset).
- * Set NOLUNS quirk as we won't be asking for
- * a lun to identify.
- */
- struct scsi_link *sc_link = sc->sc_nexus->xs->sc_link;
- printf("%s(%d,%d): "
- "MSGIN failed; trying alt selection\n",
- sc->sc_dev.dv_xname,
- sc_link->target, sc_link->lun);
- esp_sched_msgout(SEND_REJECT);
- sc->sc_tinfo[sc_link->target].flags |= T_XXX;
- sc_link->quirks |= SDEV_NOLUNS;
- if (sc->sc_state == ESP_HASNEXUS) {
- TAILQ_INSERT_HEAD(&sc->ready_list,
- sc->sc_nexus, chain);
- sc->sc_nexus = NULL;
- sc->sc_tinfo[sc_link->target].lubusy
- &= ~(1<<sc_link->lun);
- }
- esp_scsi_reset(sc);
- sc->sc_state = ESP_IDLE;
- return;
- }
- ESP_MISC(("0x%02x ", sc->sc_imess[sc->sc_imlen]));
- if (sc->sc_imlen >= ESP_MAX_MSG_LEN) {
- esp_sched_msgout(SEND_REJECT);
- sc->sc_flags |= ESP_DROP_MSGI;
- } else {
- sc->sc_imlen++;
- /*
- * This testing is suboptimal, but most
- * messages will be of the one byte variety, so
- * it should not effect performance
- * significantly.
- */
- if (sc->sc_imlen == 1 && IS1BYTEMSG(sc->sc_imess[0]))
- break;
- if (sc->sc_imlen == 2 && IS2BYTEMSG(sc->sc_imess[0]))
- break;
- if (sc->sc_imlen >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
- sc->sc_imlen == sc->sc_imess[1] + 2)
- break;
- }
+ /*
+ * If we're going to reject the message, don't bother storing
+ * the incoming bytes. But still, we need to ACK them.
+ * XXX: the above comment might be true -- this is not being
+ * done though!
+ */
+ if ((sc->sc_flags & ESPF_DROP_MSGI) == 0) {
+ x = espgetbyte(sc, 1);
+ if (x == -1) {
+ printf("%s: msgin fifo empty at %d\n",
+ sc->sc_dev.dv_xname, sc->sc_imlen);
+ if (sc->sc_espintr & ESPINTR_BS) {
+ espr->espr_cmd = ESPCMD_TRANS;
+ ESPD(("MSI:y "));
+ } else
+ ESPD(("MSI:n "));
+ return;
+ }
+ ESPD(("{%02x} ", (u_char)x));
+ sc->sc_imess[sc->sc_imlen] = (u_char)x;
+ if (sc->sc_imlen >= ESP_MSGLEN_MAX) {
+ esp_sched_msgout(SEND_REJECT);
+ DELAY(1);
+ sc->sc_flags |= ESPF_DROP_MSGI;
+ } else {
+ sc->sc_imlen++;
+ /*
+ * This testing is suboptimal, but most
+ * messages will be of the one byte variety, so
+ * it should not effect performance
+ * significantly.
+ */
+ if (sc->sc_imlen == 1 && IS1BYTEMSG(sc->sc_imess[0]))
+ goto gotit;
+ if (sc->sc_imlen == 2 && IS2BYTEMSG(sc->sc_imess[0]))
+ goto gotit;
+ if (sc->sc_imlen >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
+ sc->sc_imlen == sc->sc_imess[1] + 2)
+ goto gotit;
}
}
+ goto done;
+
+gotit:
+ ESPD(("MP["));
+ for (i=0; i<sc->sc_imlen; i++)
+ ESPD(("%02x%c", sc->sc_imess[i],
+ (i==sc->sc_imlen-1) ? ']' : ' '));
+ ESPD((" "));
+
+ sc->sc_imlen = 0; /* message is fully received */
ESP_MISC(("gotmsg "));
/*
* Now we should have a complete message (1 byte, 2 byte
* and moderately long extended messages). We only handle
* extended messages which total length is shorter than
- * ESP_MAX_MSG_LEN. Longer messages will be amputated.
+ * ESP_MSGLEN_MAX. Longer messages will be amputated.
*/
- if (sc->sc_state == ESP_HASNEXUS) {
- struct ecb *ecb = sc->sc_nexus;
- struct esp_tinfo *ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
+ if (sc->sc_state == ESPS_NEXUS ||
+ sc->sc_state == ESPS_DOINGMSGIN ||
+ sc->sc_state == ESPS_DOINGSTATUS) {
+ struct esp_tinfo *ti;
+
+ ecb = sc->sc_nexus;
+ ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
+
+ sc->sc_state = ESPS_NEXUS; /* where we go after this */
switch (sc->sc_imess[0]) {
case MSG_CMDCOMPLETE:
ESP_MISC(("cmdcomplete "));
if (!ecb) {
esp_sched_msgout(SEND_ABORT);
+ DELAY(1);
printf("%s: CMDCOMPLETE but no command?\n",
sc->sc_dev.dv_xname);
break;
}
if (sc->sc_dleft < 0) {
- struct scsi_link *sc_link = ecb->xs->sc_link;
- printf("esp: %d extra bytes from %d:%d\n",
- -sc->sc_dleft, sc_link->target, sc_link->lun);
- sc->sc_dleft = 0;
+ sc_print_addr(ecb->xs->sc_link);
+ printf("%d extra bytes\n", -sc->sc_dleft);
+ ecb->dleft = 0;
}
- ESPCMD(sc, ESPCMD_MSGOK);
ecb->xs->resid = ecb->dleft = sc->sc_dleft;
- sc->sc_flags |= ESP_BUSFREE_OK;
- return;
-
+ ecb->flags |= ECB_DONE;
+ break;
case MSG_MESSAGE_REJECT:
if (esp_debug & ESP_SHOWMISC)
- printf("%s: our msg rejected by target\n",
- sc->sc_dev.dv_xname);
- if (sc->sc_flags & ESP_SYNCHNEGO) {
- ti->period = ti->offset = 0;
- sc->sc_flags &= ~ESP_SYNCHNEGO;
+ printf("%s targ %d: our msg rejected by target\n",
+ sc->sc_dev.dv_xname,
+ ecb->xs->sc_link->target);
+ if (sc->sc_flags & ESPF_SYNCHNEGO) {
+ /*
+ * Device doesn't even know what sync is
+ * (right?)
+ */
+ ti->offset = 0;
+ ti->period = sc->sc_minsync;
+ ti->synctp = 250 / ti->period;
+ sc->sc_flags &= ~ESPF_SYNCHNEGO;
ti->flags &= ~DO_NEGOTIATE;
}
/* Not all targets understand INITIATOR_DETECTED_ERR */
- if (sc->sc_msgout == SEND_INIT_DET_ERR)
+ if (sc->sc_msgout == SEND_INIT_DET_ERR) {
esp_sched_msgout(SEND_ABORT);
- ESPCMD(sc, ESPCMD_MSGOK);
+ DELAY(1);
+ }
break;
case MSG_NOOP:
- ESPCMD(sc, ESPCMD_MSGOK);
break;
case MSG_DISCONNECT:
if (!ecb) {
esp_sched_msgout(SEND_ABORT);
+ DELAY(1);
printf("%s: nothing to DISCONNECT\n",
sc->sc_dev.dv_xname);
break;
}
- ESPCMD(sc, ESPCMD_MSGOK);
ti->dconns++;
TAILQ_INSERT_HEAD(&sc->nexus_list, ecb, chain);
ecb = sc->sc_nexus = NULL;
- sc->sc_state = ESP_IDLE;
- sc->sc_flags |= ESP_BUSFREE_OK;
+ sc->sc_state = ESPS_EXPECTDISC;
+ sc->sc_flags |= ESPF_MAYDISCON;
break;
case MSG_SAVEDATAPOINTER:
if (!ecb) {
esp_sched_msgout(SEND_ABORT);
+ DELAY(1);
printf("%s: no DATAPOINTERs to save\n",
sc->sc_dev.dv_xname);
break;
}
- ESPCMD(sc, ESPCMD_MSGOK);
+ ESPD(("DL%d/%d ", sc->sc_dleft, ecb->dleft));
ecb->dleft = sc->sc_dleft;
ecb->daddr = sc->sc_dp;
break;
case MSG_RESTOREPOINTERS:
if (!ecb) {
esp_sched_msgout(SEND_ABORT);
+ DELAY(1);
printf("%s: no DATAPOINTERs to restore\n",
sc->sc_dev.dv_xname);
break;
}
- ESPCMD(sc, ESPCMD_MSGOK);
sc->sc_dp = ecb->daddr;
sc->sc_dleft = ecb->dleft;
break;
@@ -1049,39 +1081,41 @@ esp_msgin(sc)
case MSG_EXT_SDTR:
ti->period = sc->sc_imess[3];
ti->offset = sc->sc_imess[4];
- if (ti->offset == 0) {
- printf("%s: async\n", TARGETNAME(ecb));
- ti->offset = 0;
- } else if (ti->period > 124) {
- printf("%s: async\n", TARGETNAME(ecb));
+ sc->sc_flags &= ~ESPF_SYNCHNEGO;
+ ti->flags &= ~DO_NEGOTIATE;
+ if (ti->offset == 0 ||
+ ti->offset > ESP_SYNC_MAXOFF ||
+ ti->period < sc->sc_minsync) {
ti->offset = 0;
- esp_sched_msgout(SEND_SDTR);
- } else { /* we are sync */
- printf("%s: sync rate %2fMb/s\n",
- TARGETNAME(ecb),
- sc->sc_freq/ti->period);
+ ti->period = sc->sc_minsync;
+ ti->synctp = 250 / ti->period;
+ break;
}
+ printf("%s targ %d: sync, offset %d, period %dnsec\n",
+ sc->sc_dev.dv_xname, ecb->xs->sc_link->target,
+ ti->offset, ti->period * 4);
+ ti->synctp = 250 / ti->period;
break;
- default: /* Extended messages we don't handle */
- ESPCMD(sc, ESPCMD_SETATN);
+ default:
+ /* Extended messages we don't handle */
+ esp_sched_msgout(SEND_REJECT);
+ DELAY(1);
break;
}
- ESPCMD(sc, ESPCMD_MSGOK);
break;
default:
- /* thanks for that ident... */
- if (!ESP_MSG_ISIDENT(sc->sc_imess[0])) {
- ESP_MISC(("unknown "));
- ESPCMD(sc, ESPCMD_SETATN);
+ /* thanks for that ident... XXX: we should check it? */
+ if (!MSG_ISIDENTIFY(sc->sc_imess[0])) {
+ esp_sched_msgout(SEND_REJECT);
+ DELAY(1);
}
- ESPCMD(sc, ESPCMD_MSGOK);
break;
}
- } else if (sc->sc_state == ESP_RESELECTED) {
+ } else if (sc->sc_state == ESPS_RESELECTED) {
struct scsi_link *sc_link;
- struct ecb *ecb;
u_char lunit;
- if (ESP_MSG_ISIDENT(sc->sc_imess[0])) { /* Identify? */
+
+ if (MSG_ISIDENTIFY(sc->sc_imess[0])) { /* Identify? */
ESP_MISC(("searching "));
/*
* Search wait queue for disconnected cmd
@@ -1101,37 +1135,101 @@ esp_msgin(sc)
}
}
- if (!ecb) { /* Invalid reselection! */
+ if (!ecb) {
+ /* Invalid reselection! */
esp_sched_msgout(SEND_ABORT);
+ DELAY(1);
printf("esp: invalid reselect (idbit=0x%2x)\n",
sc->sc_selid);
- } else { /* Reestablish nexus */
+ } else {
/*
+ * Reestablish nexus:
* Setup driver data structures and
* do an implicit RESTORE POINTERS
*/
sc->sc_nexus = ecb;
sc->sc_dp = ecb->daddr;
sc->sc_dleft = ecb->dleft;
- sc->sc_tinfo[sc_link->target].lubusy
- |= (1<<sc_link->lun);
- esp[ESP_SYNCOFF] =
+ sc->sc_tinfo[sc_link->target].lubusy |=
+ (1<<sc_link->lun);
+ espr->espr_syncoff =
sc->sc_tinfo[sc_link->target].offset;
- esp[ESP_SYNCTP] =
- 250 / sc->sc_tinfo[sc_link->target].period;
+ espr->espr_synctp = 250 /
+ sc->sc_tinfo[sc_link->target].period;
ESP_MISC(("... found ecb"));
- sc->sc_state = ESP_HASNEXUS;
+ sc->sc_state = ESPS_NEXUS;
}
} else {
printf("%s: bogus reselect (no IDENTIFY) %0x2x\n",
sc->sc_dev.dv_xname, sc->sc_selid);
esp_sched_msgout(SEND_DEV_RESET);
+ DELAY(1);
}
} else { /* Neither ESP_HASNEXUS nor ESP_RESELECTED! */
printf("%s: unexpected message in; will send DEV_RESET\n",
sc->sc_dev.dv_xname);
esp_sched_msgout(SEND_DEV_RESET);
+ DELAY(1);
+ }
+done:
+ espr->espr_cmd = ESPCMD_MSGOK;
+ espr->espr_cmd = ESPCMD_NOP;
+}
+
+
+void
+esp_makemsg(sc)
+ register struct esp_softc *sc;
+{
+ struct esp_tinfo *ti;
+ struct ecb *ecb = sc->sc_nexus;
+ int i;
+
+ sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
+ ESPD(("MQ%02x/%02x ", sc->sc_msgpriq, sc->sc_msgout));
+
+ sc->sc_omlen = 1; /* "Default" message len */
+ switch (sc->sc_msgout) {
+ case SEND_SDTR: /* implies an IDENTIFY message */
+ sc->sc_flags |= ESPF_SYNCHNEGO;
+ ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
+ sc->sc_omess[0] = MSG_IDENTIFY(ecb->xs->sc_link->lun,
+ !(ecb->xs->flags & SCSI_POLL));
+ sc->sc_omess[1] = MSG_EXTENDED;
+ sc->sc_omess[2] = 3;
+ sc->sc_omess[3] = MSG_EXT_SDTR;
+ sc->sc_omess[4] = ti->period;
+ sc->sc_omess[5] = ti->offset;
+ sc->sc_omlen = 6;
+ /* Fallthrough! */
+ case SEND_IDENTIFY:
+ sc->sc_omess[0] = MSG_IDENTIFY(ecb->xs->sc_link->lun,
+ !(ecb->xs->flags & SCSI_POLL));
+ break;
+ case SEND_DEV_RESET:
+ sc->sc_omess[0] = MSG_BUS_DEV_RESET;
+ if (sc->sc_nexus)
+ sc->sc_nexus->flags |= ECB_DONE;
+ break;
+ case SEND_PARITY_ERROR:
+ sc->sc_omess[0] = MSG_PARITY_ERROR;
+ break;
+ case SEND_ABORT:
+ sc->sc_omess[0] = MSG_ABORT;
+ if (sc->sc_nexus)
+ sc->sc_nexus->flags |= ECB_DONE;
+ break;
+ case SEND_INIT_DET_ERR:
+ sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
+ break;
+ case SEND_REJECT:
+ sc->sc_omess[0] = MSG_MESSAGE_REJECT;
+ break;
+ default:
+ sc->sc_omess[0] = MSG_NOOP;
+ break;
}
+ sc->sc_omp = sc->sc_omess;
}
@@ -1142,434 +1240,620 @@ void
esp_msgout(sc)
register struct esp_softc *sc;
{
- volatile caddr_t esp = sc->sc_reg;
+ struct espregs *espr = sc->sc_regs;
struct esp_tinfo *ti;
struct ecb *ecb;
+ int i;
- if (sc->sc_prevphase != MESSAGE_OUT_PHASE) {
- /* Pick up highest priority message */
- sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
- sc->sc_omlen = 1; /* "Default" message len */
- switch (sc->sc_msgout) {
- case SEND_SDTR: /* Also implies an IDENTIFY message */
- ecb = sc->sc_nexus;
- sc->sc_flags |= ESP_SYNCHNEGO;
- ti = &sc->sc_tinfo[ecb->xs->sc_link->target];
- sc->sc_omess[1] = MSG_EXTENDED;
- sc->sc_omess[2] = 3;
- sc->sc_omess[3] = MSG_EXT_SDTR;
- sc->sc_omess[4] = ti->period;
- sc->sc_omess[5] = ti->offset;
- sc->sc_omlen = 6;
- /* Fallthrough! */
- case SEND_IDENTIFY:
- if (sc->sc_state != ESP_HASNEXUS) {
- printf("esp at line %d: no nexus", __LINE__);
- Debugger();
- }
- ecb = sc->sc_nexus;
- sc->sc_omess[0] = ESP_MSG_IDENTIFY(ecb->xs->sc_link->lun);
- break;
- case SEND_DEV_RESET:
- sc->sc_omess[0] = MSG_BUS_DEV_RESET;
- sc->sc_flags |= ESP_BUSFREE_OK;
- break;
- case SEND_PARITY_ERROR:
- sc->sc_omess[0] = MSG_PARITY_ERR;
- break;
- case SEND_ABORT:
- sc->sc_omess[0] = MSG_ABORT;
- sc->sc_flags |= ESP_BUSFREE_OK;
- break;
- case SEND_INIT_DET_ERR:
- sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
- break;
- case SEND_REJECT:
- sc->sc_omess[0] = MSG_MESSAGE_REJECT;
- break;
- default:
- sc->sc_omess[0] = MSG_NOOP;
- break;
- }
- sc->sc_omp = sc->sc_omess;
- }
+ /* Pick up highest priority message */
+ sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
+ esp_makemsg(sc);
- /* (re)send the message */
- DMA_START(sc->sc_dma, &sc->sc_omp, &sc->sc_omlen, 0);
+ for (i = 0; i < sc->sc_omlen; i++)
+ espr->espr_fifo = sc->sc_omp[i];
+ espr->espr_cmd = ESPCMD_TRANS;
+}
+
+
+void
+esp_timeout(arg)
+ void *arg;
+{
+ struct ecb *ecb = (struct ecb *)arg;
+ struct esp_softc *sc;
+
+ sc = ecb->xs->sc_link->adapter_softc;
+ sc_print_addr(ecb->xs->sc_link);
+ printf("timed out at %d %d\n", sc->sc_state, sc->sc_phase);
+
+ ecb->xs->error = XS_TIMEOUT;
+ esp_reset(sc);
+ esp_done(ecb);
+ printf("new ecb %08x\n", sc->sc_nexus);
}
/*
- * This is the most critical part of the driver, and has to know
- * how to deal with *all* error conditions and phases from the SCSI
- * bus. If there are no errors and the DMA was active, then call the
- * DMA pseudo-interrupt handler. If this returns 1, then that was it
- * and we can return from here without further processing.
- *
- * Most of this needs verifying.
+ * Whatever we do, we must generate an interrupt if we expect to go
+ * to the next state.
+ * Note: this increments the events even if called from esp_poll()
*/
int
espintr(sc)
register struct esp_softc *sc;
{
+ struct espregs *espr = sc->sc_regs;
register struct ecb *ecb = sc->sc_nexus;
register struct scsi_link *sc_link;
- volatile caddr_t esp = sc->sc_reg;
+ u_char *cmd;
struct esp_tinfo *ti;
- caddr_t cmd;
- int loop;
+ int dmaintrwas, i;
- ESP_TRACE(("espintr\n"));
-
/*
- * I have made some (maybe seriously flawed) assumptions here,
- * but basic testing (uncomment the printf() below), show that
- * certainly something happens when this loop is here.
- *
- * The idea is that many of the SCSI operations take very little
- * time, and going away and getting interrupted is too high an
- * overhead to pay. For example, selecting, sending a message
- * and command and then doing some work can be done in one "pass".
- *
- * The DELAY is not variable because I do not understand that the
- * DELAY loop should be fixed-time regardless of CPU speed, but
- * I am *assuming* that the faster SCSI processors get things done
- * quicker (sending a command byte etc), and so there is no
- * need to be too slow.
- *
- * This is a heuristic. It is 2 when at 20Mhz, 2 at 25Mhz and 1
- * at 40Mhz. This needs testing.
+ * Revision 1 DMA's must have their interrupts disabled,
+ * otherwise we can get bus timeouts while reading ESP
+ * registers.
*/
- for (loop = 0; 1;loop++, DELAY(50/sc->sc_freq)) {
- /* a feeling of deja-vu */
- if (!DMA_ISINTR(sc->sc_dma) && loop)
- return 1;
-#if 0
- if (loop)
- printf("*");
-#endif
+ if (sc->sc_dma->sc_rev == DMAREV_1)
+ dmaintrwas = dmadisintr(sc->sc_dma);
- /* and what do the registers say... */
- espreadregs(sc);
+ espreadregs(sc);
- if (sc->sc_state == ESP_IDLE) {
- printf("%s: stray interrupt\n", sc->sc_dev.dv_xname);
- return 0;
- }
+ /*
+ * If either of these two things is true, we caused an interrupt.
+ * If we didn't, let's get out of here.
+ */
+ if ((sc->sc_espintr | dmapending(sc->sc_dma)) == 0) {
+ if (sc->sc_dma->sc_rev == DMAREV_1 && dmaintrwas)
+ dmaenintr(sc->sc_dma);
+ return (0);
+ }
- sc->sc_intrcnt.ev_count++;
+ sc->sc_phase = espphase(sc);
+ ESPD(("I%02x/%02x/%02x ", sc->sc_espintr, sc->sc_state, sc->sc_phase));
+
+ if (sc->sc_espintr & ESPINTR_SBR) {
+ espflush(sc);
+ printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
+ esp_init(sc, 0); /* Restart everything */
/*
- * What phase are we in when we *entered* the
- * interrupt handler ?
- *
- * On laster ESP chips (ESP236 and up) the FE (features
- * enable) bit in config 2 latches the phase bits
- * at each "command completion".
+ * No interrupt expected, since there are now no
+ * ecb's in progress.
*/
- sc->sc_phase = espphase(sc);
+ goto done;
+ }
+
+ if (sc->sc_espintr & ESPINTR_ILL) {
+ printf("%s: illegal command %02x\n",
+ sc->sc_dev.dv_xname, espr->espr_cmd);
+ if (sc->sc_state == ESPS_NEXUS) {
+ ecb->xs->error = XS_DRIVER_STUFFUP;
+ untimeout(esp_timeout, ecb);
+ esp_done(ecb);
+ }
+ esp_reset(sc);
+ esp_sched(sc); /* start next command */
+ goto done;
+ }
+
+ if (sc->sc_espstat & ESPSTAT_GE) {
+ /* no target ? */
+ espflush(sc);
+ printf("%s: gross error\n", sc->sc_dev.dv_xname);
+ if (sc->sc_state == ESPS_NEXUS) {
+ ecb->xs->error = XS_DRIVER_STUFFUP;
+ untimeout(esp_timeout, ecb);
+ esp_done(ecb);
+ }
+ esp_reset(sc);
+ esp_sched(sc);
+ /* started next command, which will interrupt us */
+ goto done;
+ }
+
+ /*
+ * The `bad interrupts' have already been checked.
+ */
+states:
+ switch (sc->sc_state) {
+ case ESPS_IDLE:
+ ESPD(("I "));
+
+ sc->sc_nexus = NULL;
+
+ if (sc->sc_espintr & ESPINTR_RESEL) {
+ sc->sc_state = ESPS_RESELECTED;
+ goto states;
+ }
+ esp_sched(sc);
/*
- * At the moment, only a SCSI Bus Reset or Illegal
- * Command are classed as errors. A diconnect is a
- * valid condition, and we let the code check is the
- * "ESP_BUSFREE_OK" flag was set before declaring it
- * and error.
- *
- * Also, the status register tells us about "Gross
- * Errors" and "Parity errors". Only the Gross Error
- * is really bad, and the parity errors are dealt
- * with later
- *
- * TODO
- * If there are too many parity error, go to slow
- * cable mode ?
+ * We will get an interrupt if esp_sched() queues
+ * anything to the scsi bus.
*/
-#define ESPINTR_ERR (ESPINTR_SBR|ESPINTR_ILL)
-
- if (sc->sc_espintr & ESPINTR_ERR ||
- sc->sc_espstat & ESPSTAT_GE) {
- /* SCSI Reset */
- if (sc->sc_espintr & ESPINTR_SBR) {
- if (esp[ESP_FFLAG] & ESPFIFO_FF) {
- ESPCMD(sc, ESPCMD_FLUSH);
- DELAY(1);
- }
- printf("%s: SCSI bus reset\n",
- sc->sc_dev.dv_xname);
- esp_init(sc, 0); /* Restart everything */
- return 1;
+ goto done;
+ case ESPS_SELECTING:
+ /*
+ * For a simple select, we sent either
+ * ESPCMD_SELATN or ESPCMD_SELNATN
+ */
+ ESPD(("S "));
+
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ sc->sc_state = ESPS_NEXUS; /* will cleanup */
+ goto states;
+ }
+
+ if (sc->sc_espintr & ESPINTR_RESEL) {
+ /*
+ * If we were trying to select a target,
+ * push our command back into the ready list.
+ */
+ if (sc->sc_state == ESPS_SELECTING) {
+ TAILQ_INSERT_HEAD(&sc->ready_list,
+ sc->sc_nexus, chain);
+ ecb = sc->sc_nexus = NULL;
}
+ sc->sc_state = ESPS_RESELECTED;
+ goto states;
+ }
- if (sc->sc_espstat & ESPSTAT_GE) {
- /* no target ? */
- if (esp[ESP_FFLAG] & ESPFIFO_FF) {
- ESPCMD(sc, ESPCMD_FLUSH);
- DELAY(1);
+ if (sc->sc_espintr == (ESPINTR_FC|ESPINTR_BS)) {
+ ESPD(("STEP%d ", sc->sc_espstep));
+ if (sc->sc_espstep == 0) {
+ /* ATN: cannot happen */
+ /* NATN: target did not assert message phase */
+ sc->sc_state = ESPS_IDLE;
+ goto states;
+ } else if (sc->sc_espstep == 2) {
+ /* BOTH: target did not assert command phase */
+ sc->sc_state = ESPS_IDLE;
+ goto states;
+ } else if (sc->sc_espstep == 3) {
+ /* BOTH: changed phase during cmd transfer */
+ ESPD(("FF%d ", espr->espr_fflag & ESPFIFO_FF));
+ if (espr->espr_fflag & ESPFIFO_FF) {
+ sc->sc_state = ESPS_IDLE;
+ goto states;
}
+ }
+
+ espr->espr_cmd = ESPCMD_NOP; /* unlatch fifo counter */
+ if (sc->sc_phase != DATA_IN_PHASE &&
+ sc->sc_tinfo[ecb->xs->sc_link->target].offset == 0) {
DELAY(1);
- if (sc->sc_state == ESP_HASNEXUS) {
- ecb->xs->error = XS_DRIVER_STUFFUP;
- untimeout(esp_timeout, ecb);
- espreadregs(sc);
- esp_done(ecb);
- }
- return 1;
+ espflush(sc);
}
- if (sc->sc_espintr & ESPINTR_ILL) {
- /* illegal command, out of sync ? */
- printf("%s: illegal command ",
- sc->sc_dev.dv_xname);
- if (esp[ESP_FFLAG] & ESPFIFO_FF) {
- ESPCMD(sc, ESPCMD_FLUSH);
- DELAY(1);
- }
- if (sc->sc_state == ESP_HASNEXUS) {
- ecb->xs->error = XS_DRIVER_STUFFUP;
- untimeout(esp_timeout, ecb);
- esp_done(ecb);
- }
- esp_reset(sc); /* so start again */
- return 1;
+ ecb = sc->sc_nexus;
+ if (!ecb)
+ panic("esp: not nexus at sc->sc_nexus");
+ sc_link = ecb->xs->sc_link;
+ ti = &sc->sc_tinfo[sc_link->target];
+ sc->sc_flags = 0;
+
+ /* Clearly we succeeded at sending the message */
+ sc->sc_msgpriq &= ~sc->sc_msgout;
+ sc->sc_msgout = 0;
+ if (sc->sc_msgpriq)
+ espr->espr_cmd = ESPCMD_SETATN;
+
+ sc->sc_dp = ecb->daddr; /* implicit RESTOREDATAPOINTERS */
+ sc->sc_dleft = ecb->dleft;
+ ti->lubusy |= (1<<sc_link->lun);
+
+ sc->sc_state = ESPS_NEXUS;
+ }
+ break; /* handle the phase */
+ case ESPS_SELECTSTOP:
+ /*
+ * We wanted to select with multiple message bytes.
+ * As a result, we needed to use SELATNS. One
+ * message byte has been sent at this point. We need
+ * to send the other bytes, then the target will either
+ * switch to command phase to fetch the command or
+ * send us a message.
+ */
+ ESPD(("SS%d ", sc->sc_espstep));
+
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ sc->sc_state = ESPS_NEXUS;
+ goto states;
+ }
+
+ if (sc->sc_espintr & ESPINTR_RESEL) {
+ /*
+ * If we were trying to select a target,
+ * push our command back into the ready list.
+ */
+ if (sc->sc_state == ESPS_SELECTING) {
+ TAILQ_INSERT_HEAD(&sc->ready_list,
+ sc->sc_nexus, chain);
+ ecb = sc->sc_nexus = NULL;
}
+ sc->sc_state = ESPS_RESELECTED;
+ goto states;
+ }
+
+ if (sc->sc_espintr & (ESPINTR_BS|ESPINTR_FC)) {
+ int i;
+
+ /*
+ * Shove the remainder of the message bytes
+ * into the fifo. After we send them, command
+ * phase will request the command...
+ */
+ espflush(sc);
+ for (i = 1; i < sc->sc_omlen; i++)
+ espr->espr_fifo = sc->sc_omp[i];
+ espr->espr_cmd = ESPCMD_TRANS;
+ sc->sc_state = ESPS_MULTMSGEND;
+ goto done;
+ }
+ goto done;
+ case ESPS_MULTMSGEND:
+ ESPD(("MME "));
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ sc->sc_state = ESPS_NEXUS;
+ goto states;
+ }
+
+ sc->sc_msgpriq &= ~sc->sc_msgout;
+ sc->sc_msgout = 0;
+
+ ESPD(("F%d ", espr->espr_fflag & ESPFIFO_FF));
+ if (espr->espr_fflag & ESPFIFO_FF) {
+ espflush(sc);
+ DELAY(1);
}
/*
- * Call if DMA is active.
- *
- * If DMA_INTR returns true, then maybe go 'round the loop
- * again in case there is no more DMA queued, but a phase
- * change is expected.
+ * If there are more messages, re-assert
+ * ATN so that we will enter MSGOUT phase
+ * again. Also, pause till that interrupt is
+ * done to see if the phase changes.
*/
- if (sc->sc_dma->sc_active && DMA_INTR(sc->sc_dma)) {
- /* If DMA active here, then go back to work... */
- if (sc->sc_dma->sc_active)
- return 1;
- DELAY(50/sc->sc_freq);
- continue;
+ if (sc->sc_msgpriq)
+ espr->espr_cmd = ESPCMD_SETATN;
+ sc->sc_state = ESPS_NEXUS;
+ goto states;
+ case ESPS_RESELECTED:
+ ESPD(("RS "));
+
+ if (sc->sc_phase != MESSAGE_IN_PHASE) {
+ printf("%s: target didn't identify\n",
+ sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ goto done;
+ }
+ esp_msgin(sc);
+ if (sc->sc_state != ESPS_NEXUS) {
+ /* IDENTIFY failed?! */
+ printf("%s: identify failed\n", sc->sc_dev.dv_xname);
+ esp_init(sc, 1);
+ goto done;
}
/*
- * check for less serious errors
+ * We will get an interrupt because of the ESPCMD_MSGOK
+ * interrupt inside esp_msgin()
+ */
+ goto done;
+ case ESPS_DOINGDMA:
+ /*
+ * Call if DMA is still active. If dmaintr() has finished,
+ * delay a while to let things settle, and then re-read the
+ * phase.
+ *
+ * XXX: should check ESPINTR_DIS
*/
if (sc->sc_espstat & ESPSTAT_PE) {
- printf("esp: SCSI bus parity error\n");
- if (sc->sc_prevphase == MESSAGE_IN_PHASE)
- esp_sched_msgout(SEND_PARITY_ERROR);
- else
- esp_sched_msgout(SEND_INIT_DET_ERR);
+ printf("%s: SCSI bus parity error\n",
+ sc->sc_dev.dv_xname);
+ esp_sched_msgout(SEND_INIT_DET_ERR);
+ /* XXX: anything else to do? */
}
- if (sc->sc_espintr & ESPINTR_DIS) {
- ESP_MISC(("disc "));
- if (esp[ESP_FFLAG] & ESPFIFO_FF) {
- ESPCMD(sc, ESPCMD_FLUSH);
- DELAY(1);
- }
+ if (sc->sc_espintr & ESPINTR_BS) {
/*
- * This command must (apparently) be issued within
- * 250mS of a disconnect. So here you are...
+ * ESP says we have changed phase, or have
+ * finished transferring all the bytes. It
+ * doesn't matter which case, either way we
+ * will let the phase determine what happens
+ * next.
*/
- ESPCMD(sc, ESPCMD_ENSEL);
- if (sc->sc_state != ESP_IDLE) {
- /* it may be OK to disconnect */
- if (!(sc->sc_flags & ESP_BUSFREE_OK))
- ecb->xs->error = XS_TIMEOUT;
- untimeout(esp_timeout, ecb);
- esp_done(ecb);
- return 1;
+ ESPD(("DOINGDMA:BS:%02x/%02x ", sc->sc_espstat,
+ espr->espr_tcl));
+ if (sc->sc_dma->sc_active) {
+ dmaintr(sc->sc_dma, 0);
+ if (sc->sc_dma->sc_active)
+ goto done;
+ }
+ } else {
+ ESPD(("DOINGDMA:cont "));
+ if (sc->sc_dma->sc_active) {
+ dmaintr(sc->sc_dma, 1);
+ if (sc->sc_dma->sc_active)
+ goto done;
}
}
- /* did a message go out OK ? This must be broken */
- if (sc->sc_prevphase == MESSAGE_OUT_PHASE &&
- sc->sc_phase != MESSAGE_OUT_PHASE) {
- /* we have sent it */
+ /* finished a DMA transaction */
+ sc->sc_flags = 0;
+
+ ecb->daddr = sc->sc_dp; /* implicit SAVEDATAPOINTERS */
+ ecb->dleft = sc->sc_dleft;
+
+ /*
+ * ESP100 strangeness -- need to fetch a new phase --
+ * why?
+ */
+ if (sc->sc_rev==ESP100 &&
+ sc->sc_tinfo[ecb->xs->sc_link->target].offset) {
+ sc->sc_espstat = espr->espr_stat & ESPSTAT_PHASE;
+ sc->sc_phase = espphase(sc);
+ /* XXX should check if sync under/overran */
+ }
+ sc->sc_state = ESPS_NEXUS;
+ break; /* handle the phase */
+ case ESPS_DOINGMSGOUT:
+ ESPD(("DMO "));
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ sc->sc_state = ESPS_NEXUS; /* will cleanup */
+ goto states;
+ }
+
+ if (sc->sc_espintr & ESPINTR_BS) {
sc->sc_msgpriq &= ~sc->sc_msgout;
sc->sc_msgout = 0;
- }
- switch (sc->sc_state) {
+ ESPD(("F%d ", espr->espr_fflag & ESPFIFO_FF));
+ if (espr->espr_fflag & ESPFIFO_FF) {
+ espflush(sc);
+ DELAY(1);
+ }
- case ESP_RESELECTED:
/*
- * we must be continuing a message ?
+ * If there are more messages, re-assert
+ * ATN so that we will enter MSGOUT phase
+ * again. Also, pause till that interrupt is
+ * done to see if the phase changes.
*/
- if (sc->sc_phase != MESSAGE_IN_PHASE) {
- printf("%s: target didn't identify\n",
- sc->sc_dev.dv_xname);
- esp_init(sc, 1);
- return 1;
- }
- esp_msgin(sc);
- if (sc->sc_state != ESP_HASNEXUS) {
- /* IDENTIFY fail?! */
- printf("%s: identify failed\n",
- sc->sc_dev.dv_xname);
- esp_init(sc, 1);
- return 1;
- }
+ if (sc->sc_msgpriq)
+ espr->espr_cmd = ESPCMD_SETATN;
break;
+ }
- case ESP_IDLE:
- case ESP_SELECTING:
+#if 0
+ if (sc->sc_espintr & ESPINTR_FC) {
+ /*
+ * XXX: the book claims that an ESPINTR_BS is
+ * generated, not ESPINTR_FC. Check if that is
+ * true.
+ */
+ }
+#endif
+ break; /* handle the phase */
+ case ESPS_DOINGMSGIN:
+ /*
+ * We receive two interrupts per message byte here: one for
+ * the MSGOK command in esp_msgin(), and one for the TRANS
+ * command below.
+ */
+ ESPD(("DMI "));
- if (sc->sc_espintr & ESPINTR_RESEL) {
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ sc->sc_state = ESPS_NEXUS; /* will cleanup */
+ goto states;
+ }
+
+ if (sc->sc_espstat & ESPSTAT_PE) {
+ printf("%s: SCSI bus parity error\n",
+ sc->sc_dev.dv_xname);
+ esp_sched_msgout(SEND_PARITY_ERROR);
+ espflush(sc);
+ sc->sc_state = ESPS_NEXUS;
+ /* XXX: are we missing some fifo handling? */
+ goto done; /* will be interrupted for MSGOUT */
+ }
+
+ /*
+ * The two interrupts we receive per byte will alternate
+ * between entering the following two if() statements.
+ * XXX: just incase, are these two if()'s in the correct
+ * order?
+ */
+ if (sc->sc_espintr & ESPINTR_BS) {
+ /*
+ * interrupted by ESPCMD_MSGOK in esp_msgin()
+ */
+ if (sc->sc_phase == MESSAGE_IN_PHASE)
+ espr->espr_cmd = ESPCMD_TRANS;
+ else {
+ ESPD(("PC "));
/*
- * If we're trying to select a
- * target ourselves, push our command
- * back into the ready list.
+ * XXX: The phase has been changed on us.
+ * This should lead us to discard the
+ * current (incomplete) message, perhaps
+ * assert an error(?), and go handle whatever
+ * new phase we are now in.
*/
- if (sc->sc_state == ESP_SELECTING) {
- ESP_MISC(("backoff selector "));
- TAILQ_INSERT_HEAD(&sc->ready_list,
- sc->sc_nexus, chain);
- sc->sc_tinfo[sc->sc_nexus->xs->sc_link->target].lubusy
- &= ~(1<<sc_link->lun);
- sc->sc_nexus = NULL;
- }
- sc->sc_state = ESP_RESELECTED;
- if (sc->sc_phase != MESSAGE_IN_PHASE) {
- /*
- * Things are seriously fucked up.
- * Pull the brakes, i.e. reset
- */
- printf("%s: target didn't identify\n",
- sc->sc_dev.dv_xname);
- esp_init(sc, 1);
- return 1;
- }
- esp_msgin(sc); /* Handle identify message */
- if (sc->sc_state != ESP_HASNEXUS) {
- /* IDENTIFY fail?! */
- printf("%s: identify failed\n",
- sc->sc_dev.dv_xname);
- esp_init(sc, 1);
- return 1;
- }
break;
}
+ goto done;
+ }
+ if (sc->sc_espintr & ESPINTR_FC) {
+ /*
+ * interrupted by ESPCMD_TRANS a few lines above.
+ */
+ esp_msgin(sc);
+ goto done;
+ }
+ goto done;
+ case ESPS_DOINGSTATUS:
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ sc->sc_state = ESPS_NEXUS; /* will cleanup */
+ goto states;
+ }
-#define ESPINTR_DONE (ESPINTR_FC|ESPINTR_BS)
- if ((sc->sc_espintr & ESPINTR_DONE) == ESPINTR_DONE) {
- ecb = sc->sc_nexus;
- if (!ecb)
- panic("esp: not nexus at sc->sc_nexus");
- sc_link = ecb->xs->sc_link;
- ti = &sc->sc_tinfo[sc_link->target];
- if (ecb->xs->flags & SCSI_RESET)
- sc->sc_msgpriq = SEND_DEV_RESET;
- else if (ti->flags & DO_NEGOTIATE)
- sc->sc_msgpriq =
- SEND_IDENTIFY | SEND_SDTR;
- else
- sc->sc_msgpriq = SEND_IDENTIFY;
- sc->sc_state = ESP_HASNEXUS;
- sc->sc_flags = 0;
- sc->sc_prevphase = INVALID_PHASE;
- sc->sc_dp = ecb->daddr;
- sc->sc_dleft = ecb->dleft;
- ti->lubusy |= (1<<sc_link->lun);
- break;
- } else if (sc->sc_espintr & ESPINTR_FC) {
- if (sc->sc_espstep != ESPSTEP_DONE)
- if (esp[ESP_FFLAG] & ESPFIFO_FF) {
- ESPCMD(sc, ESPCMD_FLUSH);
- DELAY(1);
- }
+ if (sc->sc_espintr & (ESPINTR_FC|ESPINTR_BS)) {
+ i = espgetbyte(sc, 0);
+ if (i == -1) {
+ printf("%s: ESPS_DOINGSTATUS fifo empty\n",
+ sc->sc_dev.dv_xname);
+ /* XXX: how do we cleanup from this error? */
+ goto done;
}
- /* We aren't done yet, but expect to be soon */
- DELAY(50/sc->sc_freq);
- continue;
+ if (sc->sc_espstat & ESPSTAT_PE) {
+ printf("%s: SCSI bus parity error\n",
+ sc->sc_dev.dv_xname);
+ /*
+ * Can't tell what the real status should
+ * be, so force a later check.
+ */
+ i = SCSI_CHECK;
+ }
+ ecb->stat = (u_char)i;
+ ESPD(("status=%02x ", (u_char)i));
- case ESP_HASNEXUS:
- break;
- default:
- panic("esp unknown state");
+ if (sc->sc_espintr & ESPINTR_FC) {
+ /*
+ * XXX assumes a single byte message --
+ * and what about parity errors and other
+ * possible botches inside esp_msgin?
+ */
+ esp_msgin(sc);
+ sc->sc_state = ESPS_NEXUS;
+ } else
+ sc->sc_state = ESPS_DOINGMSGIN;
+ goto done;
}
-
+ goto done;
+ case ESPS_EXPECTDISC:
/*
- * Driver is now in state ESP_HASNEXUS, i.e. we
- * have a current command working the SCSI bus.
+ * We were told to expect a disconnection interrupt.
+ * When we get it, we can go back to other work.
*/
- cmd = (caddr_t) &ecb->cmd;
- if (sc->sc_state != ESP_HASNEXUS || ecb == NULL) {
- panic("esp no nexus");
+ ESPD(("ED "));
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ espflush(sc);
+ DELAY(1);
+ espr->espr_cmd = ESPCMD_ENSEL; /* within 250ms of disconnect */
+ sc->sc_state = ESPS_IDLE;
}
+ goto states;
+ case ESPS_NEXUS:
+ ESPD(("NX "));
- switch (sc->sc_phase) {
- case MESSAGE_OUT_PHASE:
- ESP_PHASE(("MESSAGE_OUT_PHASE "));
- esp_msgout(sc);
- sc->sc_prevphase = MESSAGE_OUT_PHASE;
- break;
- case MESSAGE_IN_PHASE:
- ESP_PHASE(("MESSAGE_IN_PHASE "));
- esp_msgin(sc);
- sc->sc_prevphase = MESSAGE_IN_PHASE;
- break;
- case COMMAND_PHASE:
- /* well, this means send the command again */
- ESP_PHASE(("COMMAND_PHASE 0x%02x (%d) ",
- ecb->cmd.opcode, ecb->clen));
- if (esp[ESP_FFLAG] & ESPFIFO_FF) {
- ESPCMD(sc, ESPCMD_FLUSH);
- DELAY(1);
- }
- espselect(sc, ecb->xs->sc_link->target,
- ecb->xs->sc_link->lun, (caddr_t)&ecb->cmd,
- ecb->clen);
- sc->sc_prevphase = COMMAND_PHASE;
- break;
- case DATA_OUT_PHASE:
- ESP_PHASE(("DATA_OUT_PHASE [%d] ", sc->sc_dleft));
- ESPCMD(sc, ESPCMD_FLUSH);
- DMA_START(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, 0);
- sc->sc_prevphase = DATA_OUT_PHASE;
- break;
- case DATA_IN_PHASE:
- ESP_PHASE(("DATA_IN_PHASE "));
- ESPCMD(sc, ESPCMD_FLUSH);
- DMA_DRAIN(sc->sc_dma);
- DMA_START(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft,
- D_WRITE);
- sc->sc_prevphase = DATA_IN_PHASE;
- break;
- case STATUS_PHASE:
- ESP_PHASE(("STATUS_PHASE "));
- ESPCMD(sc, ESPCMD_ICCS);
- (void)espgetbyte(sc, &ecb->stat);
- ESP_PHASE(("0x%02x ", ecb->stat));
- sc->sc_prevphase = STATUS_PHASE;
- break;
- case INVALID_PHASE:
- break;
- case BUSFREE_PHASE:
- if (sc->sc_flags & ESP_BUSFREE_OK) {
- /*It's fun the 1st time.. */
- sc->sc_flags &= ~ESP_BUSFREE_OK;
+ if (sc->sc_espintr & ESPINTR_DIS) {
+ espflush(sc);
+ DELAY(1);
+ espr->espr_cmd = ESPCMD_ENSEL; /* within 250ms of disconnect */
+ sc->sc_msgpriq = sc->sc_msgout = 0;
+
+ ESPD(("DD:"));
+ if (ecb->flags & ECB_DONE) {
+ ESPD(("D "));
+ /* successfully finished a transaction */
+ untimeout(esp_timeout, ecb);
+ esp_done(ecb);
+ } else if (sc->sc_flags & ESPF_MAYDISCON) {
+ ESPD(("M "));
+ /* legal discon/recon is happening */
+ TAILQ_INSERT_HEAD(&sc->nexus_list,
+ ecb, chain);
+ sc->sc_nexus = NULL;
+ sc->sc_state = ESPS_IDLE;
+ sc->sc_flags &= ~ESPF_MAYDISCON;
+ goto states;
+ } else {
+ ESPD(("U "));
+ /* unexpected disconnection! fail. */
+ ecb->xs->error = XS_TIMEOUT;
+ untimeout(esp_timeout, ecb);
+ esp_done(ecb);
}
- break;
- default:
- panic("esp: bogus bus phase\n");
+ goto done;
}
+ break; /* handle the phase */
+ default:
+ printf("%s: unknown state %d\n",
+ sc->sc_dev.dv_xname, sc->sc_state);
+ panic("cannot continue");
}
-}
-void
-esp_timeout(arg)
- void *arg;
-{
- int s = splbio();
- struct ecb *ecb = (struct ecb *)arg;
- struct esp_softc *sc;
+ ecb = sc->sc_nexus;
- sc = ecb->xs->sc_link->adapter_softc;
- sc_print_addr(ecb->xs->sc_link);
- ecb->xs->error = XS_TIMEOUT;
- printf("timed out\n");
+ switch (sc->sc_phase) {
+ case MESSAGE_OUT_PHASE:
+ /*
+ * ATN was asserted, and the bus changed into MSGOUT phase.
+ * Send a message.
+ */
+ esp_msgout(sc); /* cause intr */
+ sc->sc_state = ESPS_DOINGMSGOUT;
+ break;
+ case COMMAND_PHASE:
+ /*
+ * Apparently we need to repeat the previous command.
+ */
+ espflush(sc);
+ DELAY(1);
+ cmd = (u_char *)&ecb->cmd;
+
+ ESPD(("CMD["));
+ for (i = 0; i < ecb->clen; i++)
+ ESPD(("%02x%c", cmd[i],
+ (i == ecb->clen-1) ? ']' : ' '));
+ ESPD((" "));
+
+ /* Now the command into the FIFO */
+ for (i = 0; i < ecb->clen; i++)
+ espr->espr_fifo = cmd[i];
+
+ espr->espr_cmd = ESPCMD_TRANS; /* cause intr */
+ sc->sc_state = ESPS_NEXUS;
+ break;
+ case DATA_OUT_PHASE:
+ /*
+ * We can feed the device the data now.
+ */
+ espflush(sc);
+ DELAY(1);
+ dmastart(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, 0,
+ ecb->xs->flags & SCSI_POLL); /* cause intr */
+ sc->sc_state = ESPS_DOINGDMA;
+ break;
+ case DATA_IN_PHASE:
+ /*
+ * The device is ready to give us the data.
+ */
+ dmadrain(sc->sc_dma);
+ dmastart(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, 1,
+ ecb->xs->flags & SCSI_POLL); /* cause intr */
+ sc->sc_state = ESPS_DOINGDMA;
+ break;
+ case MESSAGE_IN_PHASE:
+ espflush(sc);
+ DELAY(1);
+ espr->espr_cmd = ESPCMD_TRANS; /* cause intr */
+ sc->sc_state = ESPS_DOINGMSGIN;
+ break;
+ case STATUS_PHASE:
+ espflush(sc);
+ DELAY(1);
+ espr->espr_cmd = ESPCMD_ICCS; /* cause intr */
+ sc->sc_state = ESPS_DOINGSTATUS;
+ break;
+ default:
+ printf("%s: bogus bus phase %d\n",
+ sc->sc_dev.dv_xname);
+ break;
+ }
- esp_done(ecb);
- esp_reset(sc);
- splx(s);
+done:
+ if (sc->sc_dma->sc_rev == DMAREV_1 && dmaintrwas)
+ dmaenintr(sc->sc_dma);
+ sc->sc_intrcnt.ev_count++;
+ return (1);
}
diff --git a/sys/arch/sparc/dev/espreg.h b/sys/arch/sparc/dev/espreg.h
index b71bb29f7cb..31db483c1bc 100644
--- a/sys/arch/sparc/dev/espreg.h
+++ b/sys/arch/sparc/dev/espreg.h
@@ -1,7 +1,9 @@
-/* $NetBSD: espreg.h,v 1.6 1995/08/29 20:05:22 pk Exp $ */
+/* $NetBSD: espreg.h,v 1.5 1995/01/07 05:17:15 mycroft Exp $ */
/*
* Copyright (c) 1994 Peter Galbavy. All rights reserved.
+ * Copyright (c) 1995 Theo de Raadt. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -12,7 +14,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by Peter Galbavy.
+ * This product includes software developed by Peter Galbavy and
+ * Theo de Raadt
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -32,117 +35,137 @@
* Register addresses, relative to some base address
*/
-#define ESP_TCL 0x00 /* RW - Transfer Count Low */
-#define ESP_TCM 0x04 /* RW - Transfer Count Mid */
-#define ESP_TCH 0x38 /* RW - Transfer Count High */
- /* NOT on 53C90 */
-
-#define ESP_FIFO 0x08 /* RW - FIFO data */
-
-#define ESP_CMD 0x0c /* RW - Command (2 deep) */
-#define ESPCMD_DMA 0x80 /* DMA Bit */
-#define ESPCMD_NOP 0x00 /* No Operation */
-#define ESPCMD_FLUSH 0x01 /* Flush FIFO */
-#define ESPCMD_RSTCHIP 0x02 /* Reset Chip */
-#define ESPCMD_RSTSCSI 0x03 /* Reset SCSI Bus */
-#define ESPCMD_RESEL 0x40 /* Reselect Sequence */
-#define ESPCMD_SELNATN 0x41 /* Select without ATN */
-#define ESPCMD_SELATN 0x42 /* Select with ATN */
-#define ESPCMD_SELATNS 0x43 /* Select with ATN & Stop */
-#define ESPCMD_ENSEL 0x44 /* Enable (Re)Selection */
-#define ESPCMD_DISSEL 0x45 /* Disable (Re)Selection */
-#define ESPCMD_SELATN3 0x46 /* Select with ATN3 */
-#define ESPCMD_RESEL3 0x47 /* Reselect3 Sequence */
-#define ESPCMD_SNDMSG 0x20 /* Send Message */
-#define ESPCMD_SNDSTAT 0x21 /* Send Status */
-#define ESPCMD_SNDDATA 0x22 /* Send Data */
-#define ESPCMD_DISCSEQ 0x23 /* Disconnect Sequence */
-#define ESPCMD_TERMSEQ 0x24 /* Terminate Sequence */
-#define ESPCMD_TCCS 0x25 /* Target Command Comp Seq */
-#define ESPCMD_DISC 0x27 /* Disconnect */
-#define ESPCMD_RECMSG 0x28 /* Receive Message */
-#define ESPCMD_RECCMD 0x29 /* Receive Command */
-#define ESPCMD_RECDATA 0x2a /* Receive Data */
-#define ESPCMD_RECCSEQ 0x2b /* Receive Command Sequence*/
-#define ESPCMD_ABORT 0x04 /* Target Abort DMA */
-#define ESPCMD_TRANS 0x10 /* Transfer Information */
-#define ESPCMD_ICCS 0x11 /* Initiator Cmd Comp Seq */
-#define ESPCMD_MSGOK 0x12 /* Message Accepted */
-#define ESPCMD_TRPAD 0x18 /* Transfer Pad */
-#define ESPCMD_SETATN 0x1a /* Set ATN */
-#define ESPCMD_RSTATN 0x1b /* Reset ATN */
-
-#define ESP_STAT 0x10 /* RO - Status */
-#define ESPSTAT_INT 0x80 /* Interrupt */
-#define ESPSTAT_GE 0x40 /* Gross Error */
-#define ESPSTAT_PE 0x20 /* Parity Error */
-#define ESPSTAT_TC 0x10 /* Terminal Count */
-#define ESPSTAT_VGC 0x08 /* Valid Group Code */
-#define ESPSTAT_PHASE 0x07 /* Phase bits */
-
-#define ESP_SELID 0x10 /* WO - Select/Reselect Bus ID */
-
-#define ESP_INTR 0x14 /* RO - Interrupt */
-#define ESPINTR_SBR 0x80 /* SCSI Bus Reset */
-#define ESPINTR_ILL 0x40 /* Illegal Command */
-#define ESPINTR_DIS 0x20 /* Disconnect */
-#define ESPINTR_BS 0x10 /* Bus Service */
-#define ESPINTR_FC 0x08 /* Function Complete */
-#define ESPINTR_RESEL 0x04 /* Reselected */
-#define ESPINTR_SELATN 0x02 /* Select with ATN */
-#define ESPINTR_SEL 0x01 /* Selected */
-
-#define ESP_TIMEOUT 0x14 /* WO - Select/Reselect Timeout */
-
-#define ESP_STEP 0x18 /* RO - Sequence Step */
-#define ESPSTEP_MASK 0x07 /* the last 3 bits */
-#define ESPSTEP_DONE 0x04 /* command went out */
-
-#define ESP_SYNCTP 0x18 /* WO - Synch Transfer Period */
- /* Default 5 (53C9X) */
-
-#define ESP_FFLAG 0x1c /* RO - FIFO Flags */
-#define ESPFIFO_SS 0xe0 /* Sequence Step (Dup) */
-#define ESPFIFO_FF 0x1f /* Bytes in FIFO */
-
-#define ESP_SYNCOFF 0x1c /* WO - Synch Offset */
- /* 0 = ASYNC */
- /* 1 - 15 = SYNC bytes */
-
-#define ESP_CFG1 0x20 /* RW - Configuration #1 */
-#define ESPCFG1_SLOW 0x80 /* Slow Cable Mode */
-#define ESPCFG1_SRR 0x40 /* SCSI Reset Rep Int Dis */
-#define ESPCFG1_PTEST 0x20 /* Parity Test Mod */
-#define ESPCFG1_PARENB 0x10 /* Enable Parity Check */
-#define ESPCFG1_CTEST 0x08 /* Enable Chip Test */
-#define ESPCFG1_BUSID 0x07 /* Bus ID */
-
-#define ESP_CCF 0x24 /* WO - Clock Conversion Factor */
- /* 0 = 35.01 - 40Mhz */
- /* NEVER SET TO 1 */
- /* 2 = 10Mhz */
- /* 3 = 10.01 - 15Mhz */
- /* 4 = 15.01 - 20Mhz */
- /* 5 = 20.01 - 25Mhz */
- /* 6 = 25.01 - 30Mhz */
- /* 7 = 30.01 - 35Mhz */
-
-#define ESP_TEST 0x28 /* WO - Test (Chip Test Only) */
-
-#define ESP_CFG2 0x2c /* RW - Configuration #2 */
-#define ESPCFG2_RSVD 0xa0 /* reserved */
-#define ESPCFG2_FE 0x40 /* Features Enable */
-#define ESPCFG2_DREQ 0x10 /* DREQ High Impedance */
-#define ESPCFG2_SCSI2 0x08 /* SCSI-2 Enable */
-#define ESPCFG2_BPA 0x04 /* Target Bad Parity Abort */
-#define ESPCFG2_RPE 0x02 /* Register Parity Error */
-#define ESPCFG2_DPE 0x01 /* DMA Parity Error */
-
-/* Config #3 only on 53C9X */
-#define ESP_CFG3 0x30 /* RW - Configuration #3 */
-#define ESPCFG3_RSVD 0xe0 /* reserved */
-#define ESPCFG3_IDM 0x10 /* ID Message Res Check */
-#define ESPCFG3_QTE 0x08 /* Queue Tag Enable */
-#define ESPCFG3_CDB 0x04 /* CDB 10-bytes OK */
-#define ESPCFG3_FSCSI 0x02 /* Fast SCSI */
-#define ESPCFG3_FCLK 0x01 /* Fast Clock (>25Mhz) */
+struct espregs {
+ volatile u_char espr_tcl;
+ volatile u_char x01;
+ volatile u_char x02;
+ volatile u_char x03;
+ volatile u_char espr_tcm;
+ volatile u_char x05;
+ volatile u_char x06;
+ volatile u_char x07;
+ volatile u_char espr_fifo;
+ volatile u_char x09;
+ volatile u_char x0a;
+ volatile u_char x0b;
+ volatile u_char espr_cmd;
+ volatile u_char x0d;
+ volatile u_char x0e;
+ volatile u_char x0f;
+ volatile u_char espr_stat;
+#define espr_selid espr_stat
+ volatile u_char x11;
+ volatile u_char x12;
+ volatile u_char x13;
+ volatile u_char espr_intr;
+#define espr_timeout espr_intr
+ volatile u_char x15;
+ volatile u_char x16;
+ volatile u_char x17;
+ volatile u_char espr_step;
+#define espr_synctp espr_step
+ volatile u_char x19;
+ volatile u_char x1a;
+ volatile u_char x1b;
+ volatile u_char espr_fflag;
+#define espr_syncoff espr_fflag
+ volatile u_char x1d;
+ volatile u_char x1e;
+ volatile u_char x1f;
+ volatile u_char espr_cfg1;
+ volatile u_char x21;
+ volatile u_char x22;
+ volatile u_char x23;
+ volatile u_char espr_ccf;
+ volatile u_char x25;
+ volatile u_char x26;
+ volatile u_char x27;
+ volatile u_char espr_test;
+ volatile u_char x29;
+ volatile u_char x2a;
+ volatile u_char x2b;
+ volatile u_char espr_cfg2;
+ volatile u_char x2d;
+ volatile u_char x2e;
+ volatile u_char x2f;
+ volatile u_char espr_cfg3; /* ESP200 only */
+ volatile u_char x31;
+ volatile u_char x32;
+ volatile u_char x33;
+ volatile u_char espr_tch; /* ESP200 only */
+};
+
+#define ESPCMD_DMA 0x80 /* DMA Bit */
+#define ESPCMD_NOP 0x00 /* No Operation */
+#define ESPCMD_FLUSH 0x01 /* Flush FIFO */
+#define ESPCMD_RSTCHIP 0x02 /* Reset Chip */
+#define ESPCMD_RSTSCSI 0x03 /* Reset SCSI Bus */
+#define ESPCMD_RESEL 0x40 /* Reselect Sequence */
+#define ESPCMD_SELNATN 0x41 /* Select without ATN */
+#define ESPCMD_SELATN 0x42 /* Select with ATN */
+#define ESPCMD_SELATNS 0x43 /* Select with ATN & Stop */
+#define ESPCMD_ENSEL 0x44 /* Enable (Re)Selection */
+#define ESPCMD_DISSEL 0x45 /* Disable (Re)Selection */
+#define ESPCMD_SELATN3 0x46 /* Select with ATN3 */
+#define ESPCMD_RESEL3 0x47 /* Reselect3 Sequence */
+#define ESPCMD_SNDMSG 0x20 /* Send Message */
+#define ESPCMD_SNDSTAT 0x21 /* Send Status */
+#define ESPCMD_SNDDATA 0x22 /* Send Data */
+#define ESPCMD_DISCSEQ 0x23 /* Disconnect Sequence */
+#define ESPCMD_TERMSEQ 0x24 /* Terminate Sequence */
+#define ESPCMD_TCCS 0x25 /* Target Command Comp Seq */
+#define ESPCMD_DISC 0x27 /* Disconnect */
+#define ESPCMD_RECMSG 0x28 /* Receive Message */
+#define ESPCMD_RECCMD 0x29 /* Receive Command */
+#define ESPCMD_RECDATA 0x2a /* Receive Data */
+#define ESPCMD_RECCSEQ 0x2b /* Receive Command Sequence*/
+#define ESPCMD_ABORT 0x04 /* Target Abort DMA */
+#define ESPCMD_TRANS 0x10 /* Transfer Information */
+#define ESPCMD_ICCS 0x11 /* Initiator Cmd Comp Seq */
+#define ESPCMD_MSGOK 0x12 /* Message Accepted */
+#define ESPCMD_TRPAD 0x18 /* Transfer Pad */
+#define ESPCMD_SETATN 0x1a /* Set ATN */
+#define ESPCMD_RSTATN 0x1b /* Reset ATN */
+
+#define ESPSTAT_INT 0x80 /* Interrupt */
+#define ESPSTAT_GE 0x40 /* Gross Error */
+#define ESPSTAT_PE 0x20 /* Parity Error */
+#define ESPSTAT_TC 0x10 /* Terminal Count */
+#define ESPSTAT_VGC 0x08 /* Valid Group Code */
+#define ESPSTAT_PHASE 0x07 /* Phase bits */
+
+#define ESPINTR_SBR 0x80 /* SCSI Bus Reset */
+#define ESPINTR_ILL 0x40 /* Illegal Command */
+#define ESPINTR_DIS 0x20 /* Disconnect */
+#define ESPINTR_BS 0x10 /* Bus Service */
+#define ESPINTR_FC 0x08 /* Function Complete */
+#define ESPINTR_RESEL 0x04 /* Reselected */
+#define ESPINTR_SELATN 0x02 /* Select with ATN */
+#define ESPINTR_SEL 0x01 /* Selected */
+
+#define ESPSTEP_MASK 0x07 /* the last 3 bits */
+#define ESPSTEP_DONE 0x04 /* command went out */
+
+#define ESPFIFO_SS 0xe0 /* Sequence Step (Dup) */
+#define ESPFIFO_FF 0x1f /* Bytes in FIFO */
+
+#define ESPCFG1_SLOW 0x80 /* Slow Cable Mode */
+#define ESPCFG1_SRR 0x40 /* SCSI Reset Rep Int Dis */
+#define ESPCFG1_PTEST 0x20 /* Parity Test Mod */
+#define ESPCFG1_PARENB 0x10 /* Enable Parity Check */
+#define ESPCFG1_CTEST 0x08 /* Enable Chip Test */
+#define ESPCFG1_BUSID 0x07 /* Bus ID */
+
+#define ESPCFG2_RSVD 0xe0 /* reserved */
+#define ESPCFG2_FE 0x40 /* Features Enable */
+#define ESPCFG2_DREQ 0x10 /* DREQ High Impedance */
+#define ESPCFG2_SCSI2 0x08 /* SCSI-2 Enable */
+#define ESPCFG2_BPA 0x04 /* Target Bad Parity Abort */
+#define ESPCFG2_RPE 0x02 /* Register Parity Error */
+#define ESPCFG2_DPE 0x01 /* DMA Parity Error */
+
+#define ESPCFG3_IDM 0x10 /* ID Message Res Check */
+#define ESPCFG3_QTE 0x08 /* Queue Tag Enable */
+#define ESPCFG3_CDB 0x04 /* CDB 10-bytes OK */
+#define ESPCFG3_FSCSI 0x02 /* Fast SCSI */
+#define ESPCFG3_FCLK 0x01 /* Fast Clock (>25Mhz) */
diff --git a/sys/arch/sparc/dev/espvar.h b/sys/arch/sparc/dev/espvar.h
index 71178098b7a..cc9b42e248d 100644
--- a/sys/arch/sparc/dev/espvar.h
+++ b/sys/arch/sparc/dev/espvar.h
@@ -1,7 +1,9 @@
-/* $NetBSD: espvar.h,v 1.5 1995/08/18 10:09:57 pk Exp $ */
+/* $NetBSD: espvar.h,v 1.3 1994/11/20 20:52:12 deraadt Exp $ */
/*
* Copyright (c) 1994 Peter Galbavy. All rights reserved.
+ * Copyright (c) 1995 Theo de Raadt. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -12,7 +14,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed by Peter Galbavy.
+ * This product includes software developed by Peter Galbavy and
+ * Theo de Raadt.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -28,17 +31,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define ESP_SYNC_REQ_ACK_OFS 0
-
-#define ESP_DEBUG 0
-
-#define FREQTOCCF(freq) (((freq + 4) / 5))
-#define ESP_DEF_TIMEOUT 153
-
-/* esp revisions */
-#define ESP100 0x01
-#define ESP100A 0x02
-#define ESP200 0x03
+/* esp chip revisions */
+#define ESP100 0
+#define ESP100A 1
+#define ESP200 2
/* Grabbed from Julians SCSI aha-drivers */
#ifdef DDB
@@ -47,39 +43,36 @@ int Debugger();
#define Debugger() panic("should call debugger here (esp.c)")
#endif DDB
-typedef caddr_t physaddr;
-
-struct esp_dma_seg {
- physaddr addr;
- long len;
-};
+#define ESP_MSGLEN_MAX 8 /* maximum msglen we handle */
+#define ESP_SYNC_REQOFF 0 /* offset we request */
+#define ESP_SYNC_MAXOFF 15 /* maximum supportable sync offset */
+#if ESP_SYNC_REQOFF > ESP_SYNC_MAXOFF
+#warning requested sync offset is higher than maximum possible sync offset.
+#endif
-extern int delaycount;
-#define FUDGE(X) ((X)>>1) /* get 1 ms spincount */
-#define MINIFUDGE(X) ((X)>>4) /* get (approx) 125us spincount */
-#define NUM_CONCURRENT 7 /* Only one per target for now */
+#define FREQTOCCF(freq) (((freq + 4) / 5))
/*
- * ECB. Holds additional information for each SCSI command Comments: We
- * need a separate scsi command block because we may need to overwrite it
- * with a request sense command. Basicly, we refrain from fiddling with
- * the scsi_xfer struct (except do the expected updating of return values).
- * We'll generally update: xs->{flags,resid,error,sense,status} and
- * occasionally xs->retries.
+ * ECB. Holds additional information for each SCSI command
+ * Comments: We need a separate scsi command block because we may need
+ * to overwrite it with a request sense command. Basically, we refrain
+ * from fiddling with the scsi_xfer struct (except do the expected
+ * updating of return values). We'll generally update:
+ * xs->{flags,resid,error,sense,status} and occasionally xs->retries.
*/
struct ecb {
TAILQ_ENTRY(ecb) chain;
- struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
- int flags; /* Status */
+ struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
+ int flags; /* Status */
#define ECB_FREE 0x00
#define ECB_ACTIVE 0x01
#define ECB_DONE 0x04
#define ECB_CHKSENSE 0x08
- struct scsi_generic cmd; /* SCSI command block */
- int clen;
- char *daddr; /* Saved data pointer */
- int dleft; /* Residue */
- u_char stat; /* SCSI status byte */
+ struct scsi_generic cmd; /* SCSI command block */
+ int clen;
+ caddr_t daddr; /* Saved data pointer */
+ int dleft; /* Residue */
+ int stat; /* SCSI status byte */
};
/*
@@ -88,35 +81,32 @@ struct ecb {
* this for now. Is there a way to reliably hook it up to sc->fordriver??
*/
struct esp_tinfo {
- int cmds; /* #commands processed */
- int dconns; /* #disconnects */
- int touts; /* #timeouts */
- int perrs; /* #parity errors */
- int senses; /* #request sense commands sent */
- ushort lubusy; /* What local units/subr. are busy? */
- u_char flags;
-#define NEED_TO_RESET 0x01 /* Should send a BUS_DEV_RESET */
-#define DO_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */
-#define TARGET_BUSY 0x04 /* Target is busy, i.e. cmd in progress */
-#define T_XXX 0x08 /* Target is XXX */
- u_char period; /* Period suggestion */
- u_char offset; /* Offset suggestion */
-} tinfo_t;
+ int cmds; /* #commands processed */
+ int dconns; /* #disconnects */
+ int touts; /* #timeouts */
+ int perrs; /* #parity errors */
+ int senses; /* #request sense commands sent */
+ u_char lubusy; /* What luns are busy? */
+ u_char flags;
+#define DO_NEGOTIATE 0x01 /* (re)negotiate synchronous options */
+#define TARGET_BUSY 0x02 /* target is busy, i.e. cmd in progress */
+ u_char period; /* sync period */
+ u_char synctp; /* sync period translated for SYNCTP */
+ u_char offset; /* sync offset */
+};
/* Register a linenumber (for debugging) */
#define LOGLINE(p)
-#define ESP_SHOWECBS 0x01
-#define ESP_SHOWINTS 0x02
-#define ESP_SHOWCMDS 0x04
-#define ESP_SHOWMISC 0x08
-#define ESP_SHOWTRAC 0x10
-#define ESP_SHOWSTART 0x20
-#define ESP_SHOWPHASE 0x40
-#define ESP_SHOWDMA 0x80
+#define ESP_SHOWECBS 0x01
+#define ESP_SHOWINTS 0x02
+#define ESP_SHOWCMDS 0x04
+#define ESP_SHOWMISC 0x08
+#define ESP_SHOWTRAC 0x10
+#define ESP_SHOWSTART 0x20
+#define ESP_SHOWPHASE 0x40
-#ifdef ESP_DEBUG
-extern int esp_debug;
+#if ESP_DEBUG
#define ESP_ECBS(str) do {if (esp_debug & ESP_SHOWECBS) printf str;} while (0)
#define ESP_MISC(str) do {if (esp_debug & ESP_SHOWMISC) printf str;} while (0)
#define ESP_INTS(str) do {if (esp_debug & ESP_SHOWINTS) printf str;} while (0)
@@ -124,7 +114,6 @@ extern int esp_debug;
#define ESP_CMDS(str) do {if (esp_debug & ESP_SHOWCMDS) printf str;} while (0)
#define ESP_START(str) do {if (esp_debug & ESP_SHOWSTART) printf str;}while (0)
#define ESP_PHASE(str) do {if (esp_debug & ESP_SHOWPHASE) printf str;}while (0)
-#define ESP_DMA(str) do {if (esp_debug & ESP_SHOWDMA) printf str;}while (0)
#else
#define ESP_ECBS(str)
#define ESP_MISC(str)
@@ -133,86 +122,85 @@ extern int esp_debug;
#define ESP_CMDS(str)
#define ESP_START(str)
#define ESP_PHASE(str)
-#define ESP_DMA(str)
#endif
-#define ESP_MAX_MSG_LEN 8
-
struct esp_softc {
- struct device sc_dev; /* us as a device */
- struct sbusdev sc_sd; /* sbus device */
- struct intrhand sc_ih; /* intr handler */
- struct evcnt sc_intrcnt; /* intr count */
- struct scsi_link sc_link; /* scsi lint struct */
- volatile caddr_t sc_reg; /* the registers */
- struct dma_softc *sc_dma; /* pointer to my dma */
+ struct device sc_dev;
+ struct sbusdev sc_sd; /* sbus device */
+ struct intrhand sc_ih; /* intr handler */
+ struct evcnt sc_intrcnt; /* intr count */
+ struct scsi_link sc_link; /* scsi lint struct */
+ struct espregs *sc_regs; /* the registers */
+ struct dma_softc *sc_dma; /* corresponding DMA ctrlr */
/* register defaults */
- u_char sc_cfg1; /* Config 1 */
- u_char sc_cfg2; /* Config 2, not ESP100 */
- u_char sc_cfg3; /* Config 3, only ESP200 */
- u_char sc_ccf; /* Clock Conversion */
+ u_char sc_cfg1; /* config 1 */
+ u_char sc_cfg2; /* config 2, only ESP100A/200 */
+ u_char sc_cfg3; /* config 3, only ESP200 */
+ u_char sc_ccf; /* clock conversion */
u_char sc_timeout;
- /* register copies, see espreadregs() */
- u_char sc_espintr;
+ u_char sc_espintr; /* copies of registers */
u_char sc_espstat;
u_char sc_espstep;
u_char sc_espfflags;
+ struct bootpath *sc_bp; /* current boot path component */
+
/* Lists of command blocks */
- TAILQ_HEAD(ecb_list, ecb) free_list,
- ready_list,
- nexus_list;
+ TAILQ_HEAD(ecb_list, ecb) free_list, ready_list, nexus_list;
- struct ecb *sc_nexus; /* current command */
- struct ecb sc_ecb[8]; /* one per target */
- struct esp_tinfo sc_tinfo[8];
+ struct ecb *sc_nexus; /* current command */
+ struct ecb sc_ecb[8]; /* one per target */
+ struct esp_tinfo sc_tinfo[8];
- /* Data about the current nexus (updated for every cmd switch) */
- caddr_t sc_dp; /* Current data pointer */
- ssize_t sc_dleft; /* Data left to transfer */
+ /* data about the current nexus (updated for every cmd switch) */
+ caddr_t sc_dp; /* current data pointer */
+ size_t sc_dleft; /* data left to transfer */
- /* Adapter state */
- int sc_phase; /* Copy of what bus phase we are in */
- int sc_prevphase; /* Copy of what bus phase we were in */
- u_char sc_state; /* State applicable to the adapter */
+ /* adapter state */
+ int sc_phase; /* bus phase (based on sc_espstat) */
+ u_char sc_state; /* state applicable to the adapter */
u_char sc_flags;
u_char sc_selid;
- /* Message stuff */
- char sc_msgpriq; /* One or more messages to send (encoded) */
- char sc_msgout; /* What message is on its way out? */
- char sc_omess[ESP_MAX_MSG_LEN];
- caddr_t sc_omp; /* Message pointer (for multibyte messages) */
+ /* message stuff */
+ u_char sc_msgpriq; /* messages to send (see SEND_* below) */
+ u_char sc_msgout; /* message that is on it's way out */
+ u_char sc_omess[ESP_MSGLEN_MAX];
+ u_char *sc_omp; /* message pointer (for multibyte messages) */
size_t sc_omlen;
- char sc_imess[ESP_MAX_MSG_LEN + 1];
- caddr_t sc_imp; /* Message pointer (for multibyte messages) */
+ u_char sc_imess[ESP_MSGLEN_MAX + 1];
+ u_char *sc_imp; /* message pointer (for multibyte messages) */
size_t sc_imlen;
/* hardware/openprom stuff */
- int sc_node; /* PROM node ID */
- int sc_freq; /* Freq in HZ */
- int sc_pri; /* SBUS priority */
- int sc_id; /* our scsi id */
- int sc_rev; /* esp revision */
- int sc_minsync; /* minimum sync period / 4 */
+ int sc_node; /* PROM node ID */
+ int sc_freq; /* Freq in HZ */
+ int sc_pri; /* SBUS priority */
+ int sc_id; /* our scsi id */
+ int sc_rev; /* esp revision */
+ int sc_minsync; /* minimum sync period / 4 */
};
/* values for sc_state */
-#define ESP_IDLE 0x01 /* waiting for something to do */
-#define ESP_TMP_UNAVAIL 0x02 /* Don't accept SCSI commands */
-#define ESP_SELECTING 0x03 /* SCSI command is arbiting */
-#define ESP_RESELECTED 0x04 /* Has been reselected */
-#define ESP_HASNEXUS 0x05 /* Actively using the SCSI bus */
-#define ESP_CLEANING 0x06
+#define ESPS_IDLE 0x01 /* waiting for something to do */
+#define ESPS_EXPECTDISC 0x02 /* a disconnect is going to happen */
+#define ESPS_SELECTING 0x03 /* SCSI command is arbiting */
+#define ESPS_RESELECTED 0x04 /* has been reselected */
+#define ESPS_NEXUS 0x05 /* actively using the SCSI bus */
+#define ESPS_DOINGDMA 0x06 /* doing a DMA transaction */
+#define ESPS_DOINGMSGOUT 0x07 /* message-out in progress */
+#define ESPS_DOINGMSGIN 0x08 /* message-in in progress */
+#define ESPS_DOINGSTATUS 0x09 /* status-in in progress */
+#define ESPS_SELECTSTOP 0x0a /* sent first byte of message.. */
+#define ESPS_MULTMSGEND 0x0b /* done sending multibyte msg */
/* values for sc_flags */
-#define ESP_DROP_MSGI 0x01 /* Discard all msgs (parity err detected) */
-#define ESP_DOINGDMA 0x02 /* The FIFO data path is active! */
-#define ESP_BUSFREE_OK 0x04 /* Bus free phase is OK. */
-#define ESP_SYNCHNEGO 0x08 /* Synch negotiation in progress. */
-#define ESP_BLOCKED 0x10 /* Don't schedule new scsi bus operations */
+#define ESPF_DROP_MSGI 0x01 /* Discard all msgs (parity err detected) */
+#define ESPF_MAYDISCON 0x02 /* disconnection allowed */
+#define ESPF_DONE 0x04 /* finished transaction */
+#define ESPF_SYNCHNEGO 0x08 /* Synch negotiation in progress. */
/* values for sc_msgout */
#define SEND_DEV_RESET 0x01
@@ -223,61 +211,14 @@ struct esp_softc {
#define SEND_IDENTIFY 0x20
#define SEND_SDTR 0x40
-/*
- * Generic SCSI messages. For now we reject most of them.
- */
-/* Messages (1 byte) */ /* I/T M(andatory) or (O)ptional */
-#define MSG_CMDCOMPLETE 0x00 /* M/M */
-#define MSG_EXTENDED 0x01 /* O/O */
-#define MSG_SAVEDATAPOINTER 0x02 /* O/O */
-#define MSG_RESTOREPOINTERS 0x03 /* O/O */
-#define MSG_DISCONNECT 0x04 /* O/O */
-#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */
-#define MSG_ABORT 0x06 /* O/M */
-#define MSG_MESSAGE_REJECT 0x07 /* M/M */
-#define MSG_NOOP 0x08 /* M/M */
-#define MSG_PARITY_ERR 0x09 /* M/M */
-#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */
-#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */
-#define MSG_BUS_DEV_RESET 0x0c /* O/M */
-#define MSG_ABORT_TAG 0x0d /* O/O */
-#define MSG_CLEAR_QUEUE 0x0e /* O/O */
-#define MSG_INIT_RECOVERY 0x0f /* O/O */
-#define MSG_REL_RECOVERY 0x10 /* O/O */
-#define MSG_TERM_IO_PROC 0x11 /* O/O */
-
-/* Messages (2 byte) */
-#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
-#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */
-#define MSG_ORDERED_Q_TAG 0x22 /* O/O */
-#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */
-
-/* Identify message */
-#define ESP_MSG_IDENTIFY(lun) (0x80|(lun & 0x7)) /* XXX 0xc0=selection on */
-#define ESP_MSG_ISIDENT(m) ((m) & 0x80)
-
-/* Extended messages (opcode) */
-#define MSG_EXT_SDTR 0x01
+#define ST_MASK 0x3e /* bits 0, 6, and 7 are reserved */
-/* SCSI Status codes */
-#define ST_GOOD 0x00
-#define ST_CHKCOND 0x02
-#define ST_CONDMET 0x04
-#define ST_BUSY 0x08
-#define ST_INTERMED 0x10
-#define ST_INTERMED_CONDMET 0x14
-#define ST_RESERVATION_CONFLICT 0x18
-#define ST_CMD_TERM 0x22
-#define ST_QUEUE_FULL 0x28
-
-#define ST_MASK 0x3e /* bit 0,6,7 is reserved */
-
-/* phase bits */
+/* physical phase bits */
#define IOI 0x01
#define CDI 0x02
#define MSGI 0x04
-/* Information transfer phases */
+/* values for sc_phase (where information transfer happens) */
#define DATA_OUT_PHASE (0)
#define DATA_IN_PHASE (IOI)
#define COMMAND_PHASE (CDI)
@@ -287,32 +228,5 @@ struct esp_softc {
#define PHASE_MASK (MSGI|CDI|IOI)
-/* Some pseudo phases for getphase()*/
-#define BUSFREE_PHASE 0x100 /* Re/Selection no longer valid */
-#define INVALID_PHASE 0x101 /* Re/Selection valid, but no REQ yet */
-#define PSEUDO_PHASE 0x100 /* "pseudo" bit */
-
-#if ESP_DEBUG > 1
-#define ESPCMD(sc, cmd) printf("cmd:0x%02x ", sc->sc_reg[ESP_CMD] = cmd)
-#else
-#define ESPCMD(sc, cmd) sc->sc_reg[ESP_CMD] = cmd
-#endif
-
-#define SAME_ESP(sc, bp, ca) \
- ((bp->val[0] == ca->ca_slot && bp->val[1] == ca->ca_offset) || \
- (bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit))
-
#define TARGETNAME(ecb) \
- ((struct device *)ecb->xs->sc_link->adapter_softc)->dv_xname
-
-/* DMA macros for ESP */
-#define DMA_ENINTR(r) ((r->enintr)(r))
-#define DMA_ISINTR(r) ((r->isintr)(r))
-#define DMA_RESET(r) ((r->reset)(r))
-#define DMA_START(a, b, c, d) ((a->start)(a, b, c, d))
-#define DMA_INTR(r) ((r->intr)(r))
-
-#define DMA_DRAIN(sc) if (sc->sc_rev < DMAREV_2) { \
- DMACSR(sc) |= D_DRAIN; \
- DMAWAIT1(sc); \
- }
+ ((struct device *)(ecb)->xs->sc_link->adapter_softc)->dv_xname