diff options
author | Jason Downs <downsj@cvs.openbsd.org> | 1997-08-08 08:13:07 +0000 |
---|---|---|
committer | Jason Downs <downsj@cvs.openbsd.org> | 1997-08-08 08:13:07 +0000 |
commit | 19e72f4e42c523b94256ffd89b7ab9ac14bab51f (patch) | |
tree | 7c1fd020376caefe1dc24ec4231322956338fc82 /sys/dev/ic | |
parent | 46c443f39694837990ad4ff368f7dc0c5d52e002 (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.h | 100 | ||||
-rw-r--r-- | sys/dev/ic/ncr53c9x.c | 265 | ||||
-rw-r--r-- | sys/dev/ic/ncr53c9xreg.h | 81 | ||||
-rw-r--r-- | sys/dev/ic/ncr53c9xvar.h | 44 |
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; |