summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorJason Downs <downsj@cvs.openbsd.org>1997-08-08 08:13:07 +0000
committerJason Downs <downsj@cvs.openbsd.org>1997-08-08 08:13:07 +0000
commit19e72f4e42c523b94256ffd89b7ab9ac14bab51f (patch)
tree7c1fd020376caefe1dc24ec4231322956338fc82 /sys/dev/ic
parent46c443f39694837990ad4ff368f7dc0c5d52e002 (diff)
Mostly sync to NetBSD-current 970804.
Apologies if this breaks anyone else using the MI ESP driver...
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/intersil7170.h100
-rw-r--r--sys/dev/ic/ncr53c9x.c265
-rw-r--r--sys/dev/ic/ncr53c9xreg.h81
-rw-r--r--sys/dev/ic/ncr53c9xvar.h44
4 files changed, 416 insertions, 74 deletions
diff --git a/sys/dev/ic/intersil7170.h b/sys/dev/ic/intersil7170.h
new file mode 100644
index 00000000000..1611894c720
--- /dev/null
+++ b/sys/dev/ic/intersil7170.h
@@ -0,0 +1,100 @@
+/* $OpenBSD: intersil7170.h,v 1.1 1997/08/08 08:13:04 downsj Exp $ */
+/* $NetBSD: intersil7170.h,v 1.1 1997/05/02 06:15:28 jeremy Exp $ */
+
+/*-
+ * Copyright (c) 1996 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Adam Glass.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _INTERSIL7170_H
+#define _INTERSIL7170_H
+
+/*
+ * Driver support for the intersil7170 used in sun[34]s to provide
+ * real time clock and time-of-day support.
+ *
+ * Derived from: datasheet "ICM7170 a uP-Compatible Real-Time Clock"
+ * document #301680-005, Dec 85
+ */
+
+struct intersil_dt { /* from p. 7 of 10 */
+ u_int8_t dt_csec;
+ u_int8_t dt_hour;
+ u_int8_t dt_min;
+ u_int8_t dt_sec;
+ u_int8_t dt_month;
+ u_int8_t dt_day;
+ u_int8_t dt_year;
+ u_int8_t dt_dow;
+};
+
+struct intersil7170 {
+ struct intersil_dt counters;
+ struct intersil_dt clk_ram; /* should be ok as both are word aligned */
+ u_int8_t clk_intr_reg;
+ u_int8_t clk_cmd_reg;
+};
+
+/* bit assignments for command register, p. 6 of 10, write-only */
+#define INTERSIL_CMD_FREQ_32K 0x0
+#define INTERSIL_CMD_FREQ_1M 0x1
+#define INTERSIL_CMD_FREQ_2M 0x2
+#define INTERSIL_CMD_FREQ_4M 0x3
+
+#define INTERSIL_CMD_12HR_MODE 0x0
+#define INTERSIL_CMD_24HR_MODE 0x4
+
+#define INTERSIL_CMD_STOP 0x0
+#define INTERSIL_CMD_RUN 0x8
+
+#define INTERSIL_CMD_IDISABLE 0x0
+#define INTERSIL_CMD_IENABLE 0x10
+
+#define INTERSIL_CMD_TEST_MODE 0x20
+#define INTERSIL_CMD_NORMAL_MODE 0x0
+
+/* bit assignments for interrupt register r/w, p 7 of 10*/
+
+#define INTERSIL_INTER_ALARM 0x1 /* r/w */
+#define INTERSIL_INTER_CSECONDS 0x2 /* r/w */
+#define INTERSIL_INTER_DSECONDS 0x4 /* r/w */
+#define INTERSIL_INTER_SECONDS 0x8 /* r/w */
+#define INTERSIL_INTER_MINUTES 0x10 /* r/w */
+#define INTERSIL_INTER_HOURS 0x20 /* r/w */
+#define INTERSIL_INTER_DAYS 0x40 /* r/w */
+#define INTERSIL_INTER_PENDING 0x80 /* read-only */
+
+#define INTERSIL_INTER_BITS "\20\10PENDING\7DAYS\6HRS\5MIN\4SCDS\3DSEC\2CSEC\1ALARM"
+
+#endif /* _INTERSIL7170_H */
diff --git a/sys/dev/ic/ncr53c9x.c b/sys/dev/ic/ncr53c9x.c
index 63d12633173..8520714102a 100644
--- a/sys/dev/ic/ncr53c9x.c
+++ b/sys/dev/ic/ncr53c9x.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ncr53c9x.c,v 1.1 1997/02/27 13:57:21 briggs Exp $ */
-/* $NetBSD: ncr53c9x.c,v 1.1 1997/02/27 01:12:07 thorpej Exp $ */
+/* $OpenBSD: ncr53c9x.c,v 1.2 1997/08/08 08:13:05 downsj Exp $ */
+/* $NetBSD: ncr53c9x.c,v 1.16 1997/07/30 12:01:53 pk Exp $ */
/*
* Copyright (c) 1996 Charles M. Hannum. All rights reserved.
@@ -132,6 +132,8 @@ const char *ncr53c9x_variant_names[] = {
"ESP200",
"NCR53C94",
"NCR53C96",
+ "ESP406",
+ "FAS408",
};
/*
@@ -180,6 +182,7 @@ ncr53c9x_attach(sc, adapter, dev)
sc->sc_ccf &= 7;
/* Reset state & bus */
+ sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags;
sc->sc_state = 0;
ncr53c9x_init(sc, 1);
@@ -196,6 +199,17 @@ ncr53c9x_attach(sc, adapter, dev)
* Now try to attach all the sub-devices
*/
config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
+
+ /*
+ * Enable interupts from the SCSI core
+ */
+ if ((sc->sc_rev == NCR_VARIANT_ESP406) ||
+ (sc->sc_rev == NCR_VARIANT_FAS408)) {
+ NCR_PIOREGS(sc);
+ NCR_WRITE_REG(sc, NCR_CFG5, NCRCFG5_SINT |
+ NCR_READ_REG(sc, NCR_CFG5));
+ NCR_SCSIREGS(sc);
+ }
}
/*
@@ -221,6 +235,9 @@ ncr53c9x_reset(sc)
/* do these backwards, and fall through */
switch (sc->sc_rev) {
+ case NCR_VARIANT_ESP406:
+ case NCR_VARIANT_FAS408:
+ NCR_SCSIREGS(sc);
case NCR_VARIANT_NCR53C94:
case NCR_VARIANT_NCR53C96:
case NCR_VARIANT_ESP200:
@@ -287,13 +304,11 @@ ncr53c9x_init(sc, doreset)
/* Cancel any active commands. */
sc->sc_state = NCR_CLEANING;
if ((ecb = sc->sc_nexus) != NULL) {
- ecb->xs->error = XS_DRIVER_STUFFUP;
- untimeout(ncr53c9x_timeout, ecb);
+ ecb->xs->error = XS_TIMEOUT;
ncr53c9x_done(sc, ecb);
}
while ((ecb = sc->nexus_list.tqh_first) != NULL) {
- ecb->xs->error = XS_DRIVER_STUFFUP;
- untimeout(ncr53c9x_timeout, ecb);
+ ecb->xs->error = XS_TIMEOUT;
ncr53c9x_done(sc, ecb);
}
}
@@ -307,11 +322,10 @@ ncr53c9x_init(sc, doreset)
for (r = 0; r < 8; r++) {
struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[r];
/* XXX - config flags per target: low bits: no reselect; high bits: no synch */
- int fl = sc->sc_dev.dv_cfdata->cf_flags;
- ti->flags = ((sc->sc_minsync && !(fl & (1<<(r+8))))
+ ti->flags = ((sc->sc_minsync && !(sc->sc_cfflags & (1<<(r+8))))
? T_NEGOTIATE : 0) |
- ((fl & (1<<r)) ? T_RSELECTOFF : 0) |
+ ((sc->sc_cfflags & (1<<r)) ? T_RSELECTOFF : 0) |
T_NEED_TO_RESET;
ti->period = sc->sc_minsync;
ti->offset = 0;
@@ -322,6 +336,7 @@ ncr53c9x_init(sc, doreset)
NCRCMD(sc, NCRCMD_RSTSCSI);
} else {
sc->sc_state = NCR_IDLE;
+ ncr53c9x_sched(sc);
}
}
@@ -392,6 +407,7 @@ ncr53c9x_setsync(sc, ti)
}
}
+int ncr53c9x_dmaselect = 0;
/*
* Send a command to a target, set the driver state to NCR_SELECTING
* and let the caller take care of the rest.
@@ -411,11 +427,20 @@ ncr53c9x_select(sc, ecb)
int clen;
NCR_TRACE(("[ncr53c9x_select(t%d,l%d,cmd:%x)] ",
- sc_link->target, sc_link->lun, ecb->cmd.opcode));
+ sc_link->target, sc_link->lun, ecb->cmd.cmd.opcode));
/* new state NCR_SELECTING */
sc->sc_state = NCR_SELECTING;
+ /*
+ * Schedule the timeout now, the first time we will go away
+ * expecting to come back due to an interrupt, because it is
+ * always possible that the interrupt may never happen.
+ */
+ if ((ecb->xs->flags & SCSI_POLL) == 0)
+ timeout(ncr53c9x_timeout, ecb,
+ (ecb->timeout * hz) / 1000);
+
NCRCMD(sc, NCRCMD_FLUSH);
/*
@@ -425,6 +450,29 @@ ncr53c9x_select(sc, ecb)
NCR_WRITE_REG(sc, NCR_SELID, target);
ncr53c9x_setsync(sc, ti);
+ if (ncr53c9x_dmaselect && (ti->flags & T_NEGOTIATE) == 0) {
+ size_t dmacl;
+ ecb->cmd.id =
+ MSG_IDENTIFY(sc_link->lun, (ti->flags & T_RSELECTOFF)?0:1);
+
+ /* setup DMA transfer for command */
+ clen = ecb->clen + 1;
+ sc->sc_cmdlen = clen;
+ sc->sc_cmdp = (caddr_t)&ecb->cmd;
+ dmacl = clen;
+ NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, &dmacl);
+ /* Program the SCSI counter */
+ NCR_WRITE_REG(sc, NCR_TCL, clen);
+ NCR_WRITE_REG(sc, NCR_TCM, clen >> 8);
+ if (sc->sc_cfg2 & NCRCFG2_FE) {
+ NCR_WRITE_REG(sc, NCR_TCH, clen >> 16);
+ }
+
+ /* And get the targets attention */
+ NCRCMD(sc, NCRCMD_SELATN | NCRCMD_DMA);
+ NCRDMA_GO(sc);
+ return;
+ }
/*
* Who am I. This is where we tell the target that we are
* happy for it to disconnect etc.
@@ -439,7 +487,7 @@ ncr53c9x_select(sc, ecb)
}
/* Now the command into the FIFO */
- cmd = (u_char *)&ecb->cmd;
+ cmd = (u_char *)&ecb->cmd.cmd;
clen = ecb->clen;
while (clen--)
NCR_WRITE_REG(sc, NCR_FIFO, *cmd++);
@@ -516,21 +564,19 @@ ncr53c9x_scsi_cmd(xs)
sc_link->target));
flags = xs->flags;
- if ((ecb = ncr53c9x_get_ecb(sc, flags)) == NULL) {
- xs->error = XS_DRIVER_STUFFUP;
+ if ((ecb = ncr53c9x_get_ecb(sc, flags)) == NULL)
return TRY_AGAIN_LATER;
- }
/* Initialize ecb */
ecb->xs = xs;
ecb->timeout = xs->timeout;
- if (xs->flags & SCSI_RESET) {
+ if (flags & SCSI_RESET) {
ecb->flags |= ECB_RESET;
ecb->clen = 0;
ecb->dleft = 0;
} else {
- bcopy(xs->cmd, &ecb->cmd, xs->cmdlen);
+ bcopy(xs->cmd, &ecb->cmd.cmd, xs->cmdlen);
ecb->clen = xs->cmdlen;
ecb->daddr = xs->data;
ecb->dleft = xs->datalen;
@@ -637,7 +683,7 @@ ncr53c9x_sense(sc, ecb)
struct scsi_xfer *xs = ecb->xs;
struct scsi_link *sc_link = xs->sc_link;
struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[sc_link->target];
- struct scsi_sense *ss = (void *)&ecb->cmd;
+ struct scsi_sense *ss = (void *)&ecb->cmd.cmd;
NCR_MISC(("requesting sense "));
/* Next, setup a request sense command block */
@@ -649,6 +695,7 @@ ncr53c9x_sense(sc, ecb)
ecb->daddr = (char *)&xs->sense;
ecb->dleft = sizeof(struct scsi_sense_data);
ecb->flags |= ECB_SENSE;
+ ecb->timeout = NCR_SENSE_TIMEOUT;
ti->senses++;
if (ecb->flags & ECB_NEXUS)
ti->lubusy &= ~(1 << sc_link->lun);
@@ -676,6 +723,8 @@ ncr53c9x_done(sc, ecb)
NCR_TRACE(("[ncr53c9x_done(error:%x)] ", xs->error));
+ untimeout(ncr53c9x_timeout, ecb);
+
/*
* Now, if we've come here with no error code, i.e. we've kept the
* initial XS_NOERROR, and the status code signals that we should
@@ -685,14 +734,14 @@ ncr53c9x_done(sc, ecb)
* We don't support chk sense conditions for the request sense cmd.
*/
if (xs->error == XS_NOERROR) {
+ xs->status = ecb->stat;
if ((ecb->flags & ECB_ABORT) != 0) {
- xs->error = XS_DRIVER_STUFFUP;
+ xs->error = XS_TIMEOUT;
} else if ((ecb->flags & ECB_SENSE) != 0) {
xs->error = XS_SENSE;
} else if ((ecb->stat & ST_MASK) == SCSI_CHECK) {
/* First, save the return values */
xs->resid = ecb->dleft;
- xs->status = ecb->stat;
ncr53c9x_sense(sc, ecb);
return;
} else {
@@ -720,8 +769,10 @@ ncr53c9x_done(sc, ecb)
ti->lubusy &= ~(1 << sc_link->lun);
if (ecb == sc->sc_nexus) {
sc->sc_nexus = NULL;
- sc->sc_state = NCR_IDLE;
- ncr53c9x_sched(sc);
+ if (sc->sc_state != NCR_CLEANING) {
+ sc->sc_state = NCR_IDLE;
+ ncr53c9x_sched(sc);
+ }
} else
ncr53c9x_dequeue(sc, ecb);
@@ -942,7 +993,11 @@ gotit:
sc_link->target, sc_link->lun);
sc->sc_dleft = 0;
}
- ecb->xs->resid = ecb->dleft = sc->sc_dleft;
+ ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE)
+ ? 0
+ : sc->sc_dleft;
+ if ((ecb->flags & ECB_SENSE) == 0)
+ ecb->xs->resid = ecb->dleft;
sc->sc_state = NCR_CMDCOMPLETE;
break;
@@ -969,9 +1024,17 @@ gotit:
NCR_MSGS(("disconnect "));
ti->dconns++;
sc->sc_state = NCR_DISCONNECT;
- if ((ecb->xs->sc_link->quirks & SDEV_AUTOSAVE) == 0)
- break;
- /*FALLTHROUGH*/
+
+ /*
+ * Mark the fact that all bytes have moved. The
+ * target may not bother to do a SAVE POINTERS
+ * at this stage. This flag will set the residual
+ * count to zero on MSG COMPLETE.
+ */
+ if (sc->sc_dleft == 0)
+ ecb->flags |= ECB_TENTATIVE_DONE;
+
+ break;
case MSG_SAVEDATAPOINTER:
NCR_MSGS(("save datapointer "));
@@ -1231,8 +1294,9 @@ ncr53c9x_intr(sc)
struct ncr53c9x_tinfo *ti;
int loop;
size_t size;
+ int nfifo;
- NCR_TRACE(("[ncr53c9x_intr]"));
+ NCR_TRACE(("[ncr53c9x_intr] "));
/*
* I have made some (maybe seriously flawed) assumptions here,
@@ -1322,13 +1386,18 @@ ncr53c9x_intr(sc)
}
if (sc->sc_state == NCR_CONNECTED ||
sc->sc_state == NCR_SELECTING) {
- ecb->xs->error = XS_DRIVER_STUFFUP;
+ ecb->xs->error = XS_TIMEOUT;
ncr53c9x_done(sc, ecb);
}
return 1;
}
if (sc->sc_espintr & NCRINTR_ILL) {
+ if (sc->sc_flags & NCR_EXPECT_ILLCMD) {
+printf("%s: ILL: ESP100 work-around activated\n", sc->sc_dev.dv_xname);
+ sc->sc_flags &= ~NCR_EXPECT_ILLCMD;
+ continue;
+ }
/* illegal command, out of sync ? */
printf("%s: illegal command: 0x%x "
"(state %d, phase %x, prevphase %x)\n",
@@ -1339,10 +1408,11 @@ ncr53c9x_intr(sc)
NCRCMD(sc, NCRCMD_FLUSH);
DELAY(1);
}
- ncr53c9x_init(sc, 0); /* Restart everything */
+ ncr53c9x_init(sc, 1); /* Restart everything */
return 1;
}
}
+ sc->sc_flags &= ~NCR_EXPECT_ILLCMD;
/*
* Call if DMA is active.
@@ -1362,8 +1432,15 @@ ncr53c9x_intr(sc)
if (NCRDMA_ISACTIVE(sc))
return 1;
+ /*
+ * Note that this can happen during normal operation
+ * if we are reselected while using DMA to select
+ * a target. If this is the case, don't issue the
+ * warning.
+ */
if (sc->sc_dleft == 0 &&
- (sc->sc_espstat & NCRSTAT_TC) == 0)
+ (sc->sc_espstat & NCRSTAT_TC) == 0 &&
+ sc->sc_state != NCR_SELECTING)
printf("%s: !TC [intr %x, stat %x, step %d]"
" prevphase %x, resid %x\n",
sc->sc_dev.dv_xname,
@@ -1445,11 +1522,12 @@ ncr53c9x_intr(sc)
goto reset;
}
printf("sending REQUEST SENSE\n");
+ untimeout(ncr53c9x_timeout, ecb);
ncr53c9x_sense(sc, ecb);
goto out;
}
- ecb->xs->error = XS_DRIVER_STUFFUP;
+ ecb->xs->error = XS_TIMEOUT;
goto finish;
case NCR_DISCONNECT:
@@ -1497,6 +1575,7 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
case NCR_SELECTING:
sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0;
sc->sc_flags = 0;
+ ecb = sc->sc_nexus;
if (sc->sc_espintr & NCRINTR_RESEL) {
/*
@@ -1506,10 +1585,11 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
*/
if (sc->sc_state == NCR_SELECTING) {
NCR_MISC(("backoff selector "));
- sc_link = sc->sc_nexus->xs->sc_link;
+ untimeout(ncr53c9x_timeout, ecb);
+ sc_link = ecb->xs->sc_link;
ti = &sc->sc_tinfo[sc_link->target];
TAILQ_INSERT_HEAD(&sc->ready_list,
- sc->sc_nexus, chain);
+ ecb, chain);
ecb = sc->sc_nexus = NULL;
}
sc->sc_state = NCR_RESELECTED;
@@ -1523,13 +1603,29 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
ncr53c9x_init(sc, 1);
return 1;
}
- if ((NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)
- != 2) {
+ /*
+ * The C90 only inhibits FIFO writes until
+ * reselection is complete, instead of
+ * waiting until the interrupt status register
+ * has been read. So, if the reselect happens
+ * while we were entering a command bytes (for
+ * another target) some of those bytes can
+ * appear in the FIFO here, after the
+ * interrupt is taken.
+ */
+ nfifo = NCR_READ_REG(sc,NCR_FFLAG) & NCRFIFO_FF;
+ if (nfifo < 2 ||
+ (nfifo > 2 &&
+ sc->sc_rev != NCR_VARIANT_ESP100)) {
printf("%s: RESELECT: "
- "%d bytes in FIFO!\n",
+ "%d bytes in FIFO! "
+ "[intr %x, stat %x, step %d, prevphase %x]\n",
sc->sc_dev.dv_xname,
- NCR_READ_REG(sc, NCR_FFLAG) &
- NCRFIFO_FF);
+ nfifo,
+ sc->sc_espintr,
+ sc->sc_espstat,
+ sc->sc_espstep,
+ sc->sc_prevphase);
ncr53c9x_init(sc, 1);
return 1;
}
@@ -1538,6 +1634,10 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
/* Handle identify message */
ncr53c9x_msgin(sc);
+ if (nfifo != 2) {
+ sc->sc_flags |= NCR_EXPECT_ILLCMD;
+ NCRCMD(sc, NCRCMD_FLUSH);
+ }
if (sc->sc_state != NCR_CONNECTED) {
/* IDENTIFY fail?! */
@@ -1592,7 +1692,11 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
* went out.
* (Timing problems?)
*/
- if ((NCR_READ_REG(sc, NCR_FFLAG)
+ if (ncr53c9x_dmaselect) {
+ if (sc->sc_cmdlen == 0)
+ /* Hope for the best.. */
+ break;
+ } else if ((NCR_READ_REG(sc, NCR_FFLAG)
& NCRFIFO_FF) == 0) {
/* Hope for the best.. */
break;
@@ -1614,6 +1718,14 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
/* Select stuck at Command Phase */
NCRCMD(sc, NCRCMD_FLUSH);
case 4:
+ if (ncr53c9x_dmaselect &&
+ sc->sc_cmdlen != 0)
+ printf("(%s:%d:%d): select; "
+ "%d left in DMA buffer\n",
+ sc->sc_dev.dv_xname,
+ sc_link->target,
+ sc_link->lun,
+ sc->sc_cmdlen);
/* So far, everything went fine */
break;
}
@@ -1634,12 +1746,6 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
/* Do an implicit RESTORE POINTERS. */
sc->sc_dp = ecb->daddr;
sc->sc_dleft = ecb->dleft;
-
- /* On our first connection, schedule a timeout. */
- if ((ecb->xs->flags & SCSI_POLL) == 0)
- timeout(ncr53c9x_timeout, ecb,
- (ecb->timeout * hz) / 1000);
-
sc->sc_state = NCR_CONNECTED;
break;
} else {
@@ -1678,14 +1784,18 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
& NCRFIFO_FF) - 2;
while (i--)
(void) NCR_READ_REG(sc,
- NCR_FIFO);
+ NCR_FIFO);
}
ecb->stat = NCR_READ_REG(sc, NCR_FIFO);
msg = NCR_READ_REG(sc, NCR_FIFO);
NCR_PHASE(("<stat:(%x,%x)>", ecb->stat, msg));
if (msg == MSG_CMDCOMPLETE) {
- ecb->xs->resid = ecb->dleft =
- sc->sc_dleft;
+ ecb->dleft =
+ (ecb->flags & ECB_TENTATIVE_DONE)
+ ? 0
+ : sc->sc_dleft;
+ if ((ecb->flags & ECB_SENSE) == 0)
+ ecb->xs->resid = ecb->dleft;
sc->sc_state = NCR_CMDCOMPLETE;
} else
printf("%s: STATUS_PHASE: msg %d\n",
@@ -1739,23 +1849,47 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
}
sc->sc_prevphase = MESSAGE_IN_PHASE;
break;
- case COMMAND_PHASE: {
- /* well, this means send the command again */
- u_char *cmd = (u_char *)&ecb->cmd;
- int i;
+ case COMMAND_PHASE:
+ /*
+ * Send the command block. Normally we don't see this
+ * phase because the SEL_ATN command takes care of
+ * all this. However, we end up here if either the
+ * target or we wanted exchange some more messages
+ * first (e.g. to start negotiations).
+ */
NCR_PHASE(("COMMAND_PHASE 0x%02x (%d) ",
- ecb->cmd.opcode, ecb->clen));
+ ecb->cmd.cmd.opcode, ecb->clen));
if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
NCRCMD(sc, NCRCMD_FLUSH);
DELAY(1);
}
- /* Now the command into the FIFO */
- for (i = 0; i < ecb->clen; i++)
- NCR_WRITE_REG(sc, NCR_FIFO, *cmd++);
- NCRCMD(sc, NCRCMD_TRANS);
- sc->sc_prevphase = COMMAND_PHASE;
+ if (ncr53c9x_dmaselect) {
+ size_t size;
+ /* setup DMA transfer for command */
+ size = ecb->clen;
+ sc->sc_cmdlen = size;
+ sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd;
+ NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen,
+ 0, &size);
+ /* Program the SCSI counter */
+ NCR_WRITE_REG(sc, NCR_TCL, size);
+ NCR_WRITE_REG(sc, NCR_TCM, size >> 8);
+ if (sc->sc_cfg2 & NCRCFG2_FE) {
+ NCR_WRITE_REG(sc, NCR_TCH, size >> 16);
+ }
+
+ NCRCMD(sc, NCRCMD_TRANS | NCRCMD_DMA);
+ NCRDMA_GO(sc);
+ } else {
+ u_char *cmd = (u_char *)&ecb->cmd.cmd;
+ int i;
+ /* Now the command into the FIFO */
+ for (i = 0; i < ecb->clen; i++)
+ NCR_WRITE_REG(sc, NCR_FIFO, *cmd++);
+ NCRCMD(sc, NCRCMD_TRANS);
}
+ sc->sc_prevphase = COMMAND_PHASE;
break;
case DATA_OUT_PHASE:
NCR_PHASE(("DATA_OUT_PHASE [%ld] ",(long)sc->sc_dleft));
@@ -1774,6 +1908,9 @@ if (sc->sc_flags & NCR_ICCS) printf("[[esp: BUMMER]]");
1, &size);
sc->sc_prevphase = DATA_IN_PHASE;
setup_xfer:
+ /* Target returned to data phase: wipe "done" memory */
+ ecb->flags &= ~ECB_TENTATIVE_DONE;
+
/* Program the SCSI counter */
NCR_WRITE_REG(sc, NCR_TCL, size);
NCR_WRITE_REG(sc, NCR_TCM, size >> 8);
@@ -1815,7 +1952,6 @@ reset:
return 1;
finish:
- untimeout(ncr53c9x_timeout, ecb);
ncr53c9x_done(sc, ecb);
goto out;
@@ -1869,6 +2005,7 @@ ncr53c9x_timeout(arg)
struct scsi_xfer *xs = ecb->xs;
struct scsi_link *sc_link = xs->sc_link;
struct ncr53c9x_softc *sc = sc_link->adapter_softc;
+ struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[sc_link->target];
int s;
sc_print_addr(sc_link);
@@ -1880,7 +2017,7 @@ ncr53c9x_timeout(arg)
sc->sc_state, sc->sc_nexus, sc->sc_phase, sc->sc_prevphase,
(long)sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout,
NCRDMA_ISACTIVE(sc) ? "DMA active" : "");
-#if NCR53C9X_DEBUG > 0
+#if NCR53C9X_DEBUG > 1
printf("TRACE: %s.", ecb->trace);
#endif
@@ -1889,12 +2026,22 @@ ncr53c9x_timeout(arg)
if (ecb->flags & ECB_ABORT) {
/* abort timed out */
printf(" AGAIN\n");
+
ncr53c9x_init(sc, 1);
} else {
/* abort the operation that has timed out */
printf("\n");
xs->error = XS_TIMEOUT;
ncr53c9x_abort(sc, ecb);
+
+ /* Disable sync mode if stuck in a data phase */
+ if (ecb == sc->sc_nexus &&
+ (ti->flags & T_SYNCMODE) != 0 &&
+ (sc->sc_phase & (MSGI|CDI)) == 0) {
+ sc_print_addr(sc_link);
+ printf("sync negotiation disabled\n");
+ sc->sc_cfflags |= (1<<(sc_link->target+8));
+ }
}
splx(s);
diff --git a/sys/dev/ic/ncr53c9xreg.h b/sys/dev/ic/ncr53c9xreg.h
index 4b848ed8c2a..d5afaf2759f 100644
--- a/sys/dev/ic/ncr53c9xreg.h
+++ b/sys/dev/ic/ncr53c9xreg.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: ncr53c9xreg.h,v 1.1 1997/02/27 13:57:23 briggs Exp $ */
-/* $NetBSD: ncr53c9xreg.h,v 1.1 1997/02/27 01:12:08 thorpej Exp $ */
+/* $OpenBSD: ncr53c9xreg.h,v 1.2 1997/08/08 08:13:06 downsj Exp $ */
+/* $NetBSD: ncr53c9xreg.h,v 1.4 1997/05/17 20:56:55 pk Exp $ */
/*
* Copyright (c) 1994 Peter Galbavy. All rights reserved.
@@ -148,3 +148,80 @@
#define NCRCFG3_CDB 0x04 /* CDB 10-bytes OK */
#define NCRCFG3_FSCSI 0x02 /* Fast SCSI */
#define NCRCFG3_FCLK 0x01 /* Fast Clock (>25Mhz) */
+
+/*
+ * For some unknown reason, the ESP406/FAS408 looks like every
+ * other ncr53c9x, except for configuration #3 register. At any
+ * rate, if you're dealing with these chips, you need to use these
+ * defines instead.
+ */
+
+/* Config #3 different on ESP406/FAS408 */
+#define NCR_ESPCFG3 0x0c /* RW - Configuration #3 */
+#define NCRESPCFG3_IDM 0x80 /* ID Message Res Check */
+#define NCRESPCFG3_QTE 0x40 /* Queue Tag Enable */
+#define NCRESPCFG3_CDB 0x20 /* CDB 10-bytes OK */
+#define NCRESPCFG3_FSCSI 0x10 /* Fast SCSI */
+#define NCRESPCFG3_SRESB 0x08 /* Save Residual Byte */
+#define NCRESPCFG3_FCLK 0x04 /* Fast Clock (>25Mhz) */
+#define NCRESPCFG3_ADMA 0x02 /* Alternate DMA Mode */
+#define NCRESPCFG3_T8M 0x01 /* Threshold 8 Mode */
+
+/* Config #4 only on ESP406/FAS408 */
+#define NCR_CFG4 0x0d /* RW - Configuration #4 */
+#define NCRCFG4_CRS1 0x80 /* Select register set #1 */
+#define NCRCFG4_RSVD 0x7b /* reserved */
+#define NCRCFG4_ACTNEG 0x04 /* Active negation */
+
+#define NCR_SCSIREGS(sc) do { NCR_WRITE_REG(sc, NCR_CFG4, \
+ ~NCRCFG4_CRS1 & NCR_READ_REG(sc, NCR_CFG4)); } while(0)
+#define NCR_PIOREGS(sc) do { NCR_WRITE_REG(sc, NCR_CFG4, \
+ NCRCFG4_CRS1 | NCR_READ_REG(sc, NCR_CFG4)); } while(0)
+
+/*
+ The following registers are only on the ESP406/FAS408. The
+ documentation refers to them as "Control Register Set #1".
+ These are the registers that are visible when bit 7 of
+ register 0x0d is set. This bit is common to both register sets.
+*/
+
+#define NCR_JMP 0x00 /* RO - Jumper Sense Register */
+#define NCRJMP_RSVD 0xc0 /* reserved */
+#define NCRJMP_ROMSZ 0x20 /* ROM Size 1=16K, 0=32K */
+#define NCRJMP_J4 0x10 /* Jumper #4 */
+#define NCRJMP_J3 0x08 /* Jumper #3 */
+#define NCRJMP_J2 0x04 /* Jumper #2 */
+#define NCRJMP_J1 0x02 /* Jumper #1 */
+#define NCRJMP_J0 0x01 /* Jumper #0 */
+
+#define NCR_PIOFIFO 0x04 /* WO - PIO FIFO, 4 bytes deep */
+
+#define NCR_PSTAT 0x08 /* RW - PIO Status Register */
+#define NCRPSTAT_PERR 0x80 /* PIO Error */
+#define NCRPSTAT_SIRQ 0x40 /* Active High of SCSI IRQ */
+#define NCRPSTAT_ATAI 0x20 /* ATA IRQ */
+#define NCRPSTAT_FEMPT 0x10 /* PIO FIFO Empty */
+#define NCRPSTAT_F13 0x08 /* PIO FIFO 1/3 */
+#define NCRPSTAT_F23 0x04 /* PIO FIFO 2/3 */
+#define NCRPSTAT_FFULL 0x02 /* PIO FIFO Full */
+#define NCRPSTAT_PIOM 0x01 /* PIO/DMA Mode */
+
+#define NCR_PIOI 0x0b /* RW - PIO Interrupt Enable */
+#define NCRPIOI_RSVD 0xe0 /* reserved */
+#define NCRPIOI_EMPTY 0x10 /* IRQ When Empty */
+#define NCRPIOI_13 0x08 /* IRQ When 1/3 */
+#define NCRPIOI_23 0x04 /* IRQ When 2/3 */
+#define NCRPIOI_FULL 0x02 /* IRQ When Full */
+#define NCRPIOI_FINV 0x01 /* Flag Invert */
+
+#define NCR_CFG5 0x0d /* RW - Configuration #5 */
+#define NCRCFG5_CRS1 0x80 /* Select Register Set #1 */
+#define NCRCFG5_SRAM 0x40 /* SRAM Memory Map */
+#define NCRCFG5_AADDR 0x20 /* Auto Address */
+#define NCRCFG5_PTRINC 0x10 /* Pointer Increment */
+#define NCRCFG5_LOWPWR 0x08 /* Low Power Mode */
+#define NCRCFG5_SINT 0x04 /* SCSI Interupt Enable */
+#define NCRCFG5_INTP 0x02 /* INT Polarity */
+#define NCRCFG5_AINT 0x01 /* ATA Interupt Enable */
+
+#define NCR_SIGNTR 0x0e /* RO - Signature */
diff --git a/sys/dev/ic/ncr53c9xvar.h b/sys/dev/ic/ncr53c9xvar.h
index e217cf77905..ee0bd451c8c 100644
--- a/sys/dev/ic/ncr53c9xvar.h
+++ b/sys/dev/ic/ncr53c9xvar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: ncr53c9xvar.h,v 1.1 1997/02/27 13:57:23 briggs Exp $ */
-/* $NetBSD: ncr53c9xvar.h,v 1.1 1997/02/27 01:12:09 thorpej Exp $ */
+/* $OpenBSD: ncr53c9xvar.h,v 1.2 1997/08/08 08:13:06 downsj Exp $ */
+/* $NetBSD: ncr53c9xvar.h,v 1.8 1997/07/30 11:48:32 pk Exp $ */
/*
* Copyright (c) 1997 Jason R. Thorpe.
@@ -61,9 +61,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define NCR53C9X_DEBUG 0
+/* Set this to 1 for normal debug, or 2 for per-target tracing. */
+#define NCR53C9X_DEBUG 1
#define NCR_ABORT_TIMEOUT 2000 /* time to wait for abort */
+#define NCR_SENSE_TIMEOUT 1000 /* time to wait for sense */
#define FREQTOCCF(freq) (((freq + 4) / 5))
@@ -76,7 +78,9 @@
#define NCR_VARIANT_ESP200 2
#define NCR_VARIANT_NCR53C94 3
#define NCR_VARIANT_NCR53C96 4
-#define NCR_VARIANT_MAX 5
+#define NCR_VARIANT_ESP406 5
+#define NCR_VARIANT_FAS408 6
+#define NCR_VARIANT_MAX 7
/*
* ECB. Holds additional information for each SCSI command Comments: We
@@ -90,24 +94,29 @@ struct ncr53c9x_ecb {
TAILQ_ENTRY(ncr53c9x_ecb) chain;
struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */
int flags;
-#define ECB_ALLOC 0x01
-#define ECB_NEXUS 0x02
-#define ECB_SENSE 0x04
-#define ECB_ABORT 0x40
-#define ECB_RESET 0x80
+#define ECB_ALLOC 0x01
+#define ECB_NEXUS 0x02
+#define ECB_SENSE 0x04
+#define ECB_ABORT 0x40
+#define ECB_RESET 0x80
+#define ECB_TENTATIVE_DONE 0x100
int timeout;
- struct scsi_generic cmd; /* SCSI command block */
- int clen;
+ struct {
+ u_char id; /* Selection Id msg */
+ struct scsi_generic cmd; /* SCSI command block */
+ } cmd;
+ int clen; /* Size of command in cmd.cmd */
char *daddr; /* Saved data pointer */
int dleft; /* Residue */
u_char stat; /* SCSI status byte */
+ u_char pad[3];
-#if NCR53C9X_DEBUG > 0
+#if NCR53C9X_DEBUG > 1
char trace[1000];
#endif
};
-#if NCR53C9X_DEBUG > 0
+#if NCR53C9X_DEBUG > 1
#define ECB_TRACE(ecb, msg, a, b) do { \
const char *f = "[" msg "]"; \
int n = strlen((ecb)->trace); \
@@ -139,6 +148,7 @@ struct ncr53c9x_tinfo {
#define T_RSELECTOFF 0x20 /* .. */
u_char period; /* Period suggestion */
u_char offset; /* Offset suggestion */
+ u_char pad[3];
} tinfo_t;
/* Register a linenumber (for debugging) */
@@ -219,6 +229,8 @@ struct ncr53c9x_softc {
struct ncr53c9x_glue *sc_glue; /* glue to MD code */
+ int sc_cfflags; /* Copy of config flags */
+
/* register defaults */
u_char sc_cfg1; /* Config 1 */
u_char sc_cfg2; /* Config 2, not ESP100 */
@@ -264,6 +276,9 @@ struct ncr53c9x_softc {
caddr_t sc_imp; /* Message pointer (for multibyte messages) */
size_t sc_imlen;
+ caddr_t sc_cmdp; /* Command pointer (for DMAed commands) */
+ size_t sc_cmdlen; /* Size of command in transit */
+
/* hardware/openprom stuff */
int sc_freq; /* Freq in HZ */
int sc_id; /* our scsi id */
@@ -290,6 +305,7 @@ struct ncr53c9x_softc {
#define NCR_ICCS 0x10 /* Expect status phase results */
#define NCR_WAITI 0x20 /* Waiting for non-DMA data to arrive */
#define NCR_ATN 0x40 /* ATN asserted */
+#define NCR_EXPECT_ILLCMD 0x80 /* Expect Illegal Command Interrupt */
/* values for sc_msgout */
#define SEND_DEV_RESET 0x01
@@ -366,3 +382,5 @@ void ncr53c9x_attach __P((struct ncr53c9x_softc *,
int ncr53c9x_scsi_cmd __P((struct scsi_xfer *));
void ncr53c9x_reset __P((struct ncr53c9x_softc *));
int ncr53c9x_intr __P((struct ncr53c9x_softc *));
+
+extern int ncr53c9x_dmaselect;