summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--distrib/notes/i386/hardware2
-rw-r--r--share/man/man4/Makefile6
-rw-r--r--share/man/man4/pci.46
-rw-r--r--share/man/man4/trm.467
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/ic/trm.c2980
-rw-r--r--sys/dev/ic/trm.h529
-rw-r--r--sys/dev/pci/files.pci6
-rw-r--r--sys/dev/pci/trm_pci.c169
9 files changed, 3765 insertions, 6 deletions
diff --git a/distrib/notes/i386/hardware b/distrib/notes/i386/hardware
index 6f116d2cb58..a56c7e62324 100644
--- a/distrib/notes/i386/hardware
+++ b/distrib/notes/i386/hardware
@@ -117,6 +117,8 @@ Supported hardware {:-include-:}:
name cards, old ASUS cards, the DTC-3130 series,
Diamond Fireport series, etc.)
Tekram DC-300B and DC-320E (Adaptec AHA-154x clones)
+ Tekram DC-3x5U (DC-315U, DC-395U/UW/F) TRM-S1040 based
+ PCI SCSI host adapters
Ultrastor 14f, 24f, and 34f
WD-7000 SCSI host adapters
RAID and Cache Controllers
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index f7d67e96753..f673c8d6d50 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.189 2002/01/24 23:00:05 mickey Exp $
+# $OpenBSD: Makefile,v 1.190 2002/02/18 01:55:30 krw Exp $
MAN= aac.4 ac97.4 addcom.4 adv.4 aha.4 ahb.4 ahc.4 aic.4 ami.4 amphy.4 \
an.4 aria.4 ast.4 atalk.4 atapiscsi.4 \
@@ -24,8 +24,8 @@ MAN= aac.4 ac97.4 addcom.4 adv.4 aha.4 ahb.4 ahc.4 aic.4 ami.4 amphy.4 \
rlphy.4 route.4 rt.4 rtii.4 \
scsi.4 sd.4 ses.4 sf.4 sf2r.4 sf4r.4 siop.4 sis.4 sk.4 sl.4 sm.4 \
spp.4 sppp.4 sqphy.4 ss.4 st.4 ste.4 stge.4 sv.4 \
- tb.4 tcic.4 tcp.4 termios.4 \
- ti.4 tl.4 tlphy.4 tp.4 tqphy.4 tty.4 tun.4 twe.4 tx.4 txp.4 txphy.4 \
+ tb.4 tcic.4 tcp.4 termios.4 ti.4 tl.4 tlphy.4 \
+ tp.4 tqphy.4 trm.4 tty.4 tun.4 twe.4 tx.4 txp.4 txphy.4 \
uaudio.4 ubsec.4 ucom.4 udp.4 uftdi.4 ugen.4 uhci.4 uhid.4 uk.4 ukbd.4 \
ukphy.4 ulpt.4 umodem.4 ums.4 umass.4 unix.4 upl.4 uplcom.4 urio.4 \
usb.4 uscanner.4 usscanner.4 uvisor.4 uyap.4 vga.4 vlan.4 vnd.4 vr.4 \
diff --git a/share/man/man4/pci.4 b/share/man/man4/pci.4
index f821aa9011f..dc948cba563 100644
--- a/share/man/man4/pci.4
+++ b/share/man/man4/pci.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pci.4,v 1.58 2002/01/24 22:43:55 mickey Exp $
+.\" $OpenBSD: pci.4,v 1.59 2002/02/18 01:55:30 krw Exp $
.\" $NetBSD: pci.4,v 1.29 2000/04/01 00:32:23 tsarna Exp $
.\"
.\" Copyright (c) 2000 Theo de Raadt. All rights reserved.
@@ -110,6 +110,10 @@ interfaces.
AMD Am53c974 PCscsi-PCI
.Tn SCSI
interfaces.
+.It Xr trm 4
+Tekram DC-3x5U (TRM-S1040 based)
+.Tn SCSI
+interfaces.
.El
.Ss RAID and cache controllers
.Bl -tag -width 10n -offset ind
diff --git a/share/man/man4/trm.4 b/share/man/man4/trm.4
new file mode 100644
index 00000000000..2d0683246af
--- /dev/null
+++ b/share/man/man4/trm.4
@@ -0,0 +1,67 @@
+.\" $OpenBSD: trm.4,v 1.1 2002/02/18 01:55:30 krw Exp $
+.\"
+.\" Copyright (c) 2001-2002, Ashley R. Martens and Kenneth R. Westerback.
+.\" All rights reserved.
+.\"
+.\" 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. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\"
+.Dd February 16, 2002
+.Dt TRM 4
+.Os
+.Sh NAME
+.Nm trm
+.Nd TRM-S1040 based PCI SCSI Host Adapters
+.Sh SYNOPSIS
+.Cd "trm* at pci? dev ? function ?"
+.Cd "scsibus* at trm?"
+.Sh DESCRIPTION
+The
+.Nm
+driver supports PCI SCSI host adapters based on Tekram's TRM-S1040
+chip, including the following:
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+Tekram DC395U/UW/F
+.It
+Tekram DC315/U
+.El
+.Sh SEE ALSO
+.Xr cd 4 ,
+.Xr intro 4 ,
+.Xr scsi 4 ,
+.Xr sd 4 ,
+.Xr st 4
+.Pp
+.Pa http://www.tekram.com/
+.Sh AUTHORS
+The
+.Nm
+driver was written for
+.Ox
+by Kenneth R. Westerback and Ashley R. Martens, based on a
+.Nx
+driver by Erich Chen, which was ported to
+.Ox
+by Martin Akesson.
diff --git a/sys/conf/files b/sys/conf/files
index 2397a7df7a8..5fccc90a7a4 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.238 2002/02/16 04:36:33 smurph Exp $
+# $OpenBSD: files,v 1.239 2002/02/18 01:55:30 krw Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -267,6 +267,10 @@ file dev/ic/sti.c sti & (sti_pci | sti_sgc) needs-flag
device iha: scsi
file dev/ic/iha.c iha
+# Tekram TRM-S1040 SCSI Cards (DC395U/UW/F,DC315/U)
+device trm: scsi
+file dev/ic/trm.c trm
+
# Attributes which machine-independent bus support can be attached to.
# These should be defined here, because some of these busses can have
# devices which provide these attributes, and we'd like to avoid hairy
diff --git a/sys/dev/ic/trm.c b/sys/dev/ic/trm.c
new file mode 100644
index 00000000000..5e0e9224974
--- /dev/null
+++ b/sys/dev/ic/trm.c
@@ -0,0 +1,2980 @@
+/* $OpenBSD: trm.c,v 1.1 2002/02/18 01:55:30 krw Exp $
+ * ------------------------------------------------------------
+ * O.S : OpenBSD
+ * File Name : trm.c
+ * Device Driver for Tekram DC395U/UW/F,DC315/U
+ * PCI SCSI Bus Master Host Adapter
+ * (SCSI chip set used Tekram ASIC TRM-S1040)
+ *
+ * (C)Copyright 1995-1999 Tekram Technology Co., Ltd.
+ * (C)Copyright 2001-2002 Ashley R. Martens and Kenneth R Westerback
+ * ------------------------------------------------------------
+ * HISTORY:
+ *
+ * REV# DATE NAME DESCRIPTION
+ * 1.00 05/01/99 ERICH CHEN First released for NetBSD 1.4.x
+ * 1.01 00/00/00 MARTIN AKESSON Port to OpenBSD 2.8
+ * 1.02 09/19/01 ASHLEY MARTENS Cleanup and formatting
+ * 2.00 01/00/02 KENNETH R WESTERBACK Rewrite of the bus and code logic
+ * ------------------------------------------------------------
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * ------------------------------------------------------------
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <scsi/scsi_message.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/ic/trm.h>
+
+/* #define TRM_DEBUG0 */
+
+void trm_minphys(struct buf *);
+
+void trm_initSRB(struct trm_scsi_req_q *);
+
+void trm_check_eeprom(struct trm_adapter_nvram *, bus_space_tag_t, bus_space_handle_t);
+void trm_read_all (struct trm_adapter_nvram *, bus_space_tag_t, bus_space_handle_t);
+void trm_write_all (struct trm_adapter_nvram *, bus_space_tag_t, bus_space_handle_t);
+
+void trm_set_data (bus_space_tag_t, bus_space_handle_t, u_int8_t, u_int8_t);
+void trm_write_cmd(bus_space_tag_t, bus_space_handle_t, u_int8_t, u_int8_t);
+
+u_int8_t trm_get_data(bus_space_tag_t, bus_space_handle_t, u_int8_t);
+
+void trm_wait_30us(bus_space_tag_t, bus_space_handle_t);
+
+int trm_scsi_cmd(struct scsi_xfer *);
+
+struct trm_scsi_req_q *trm_GetFreeSRB(struct trm_softc *);
+
+void trm_DataOutPhase0(struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_DataInPhase0 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_StatusPhase0 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_MsgOutPhase0 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_MsgInPhase0 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_DataOutPhase1(struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_DataInPhase1 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_CommandPhase1(struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_StatusPhase1 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_MsgOutPhase1 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_MsgInPhase1 (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+void trm_Nop (struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+
+void trm_SetXferParams (struct trm_softc *, struct trm_dcb *, int);
+
+void trm_DataIO_transfer(struct trm_softc *, struct trm_scsi_req_q *, u_int16_t);
+
+int trm_StartSRB (struct trm_softc *, struct trm_scsi_req_q *);
+void trm_ReleaseSRB (struct trm_softc *, struct trm_scsi_req_q *);
+void trm_RewaitSRB (struct trm_softc *, struct trm_scsi_req_q *);
+void trm_FinishSRB (struct trm_softc *, struct trm_scsi_req_q *);
+void trm_RequestSense(struct trm_softc *, struct trm_scsi_req_q *);
+
+void trm_initAdapter (struct trm_softc *);
+void trm_Disconnect (struct trm_softc *);
+void trm_Reselect (struct trm_softc *);
+void trm_GoingSRB_Done (struct trm_softc *);
+void trm_ScsiRstDetect (struct trm_softc *);
+void trm_ResetSCSIBus (struct trm_softc *);
+void trm_reset (struct trm_softc *);
+void trm_StartWaitingSRB (struct trm_softc *);
+void trm_ResetAllDevParam(struct trm_softc *);
+void trm_RecoverSRB (struct trm_softc *);
+void trm_linkSRB (struct trm_softc *);
+
+void trm_initACB(struct trm_softc *, int);
+
+void trm_ResetDevParam(struct trm_softc *, struct trm_dcb *, u_int8_t);
+
+void trm_EnableMsgOut(struct trm_softc *, u_int8_t);
+
+void trm_timeout(void *);
+
+void trm_print_info(struct trm_softc *, struct trm_dcb *);
+
+/*
+ * Define structures
+ */
+struct cfdriver trm_cd = {
+ NULL,
+ "trm",
+ DV_DULL,
+ 0,
+ 0
+};
+
+struct scsi_adapter trm_switch = {
+ trm_scsi_cmd,
+ trm_minphys,
+ NULL,
+ NULL
+};
+
+static struct scsi_device trm_device = {
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+};
+
+/*
+ * ------------------------------------------------------------
+ *
+ * stateV = (void *) trm_SCSI_phase0[phase]
+ *
+ * ------------------------------------------------------------
+ */
+static void *trm_SCSI_phase0[8] = {
+ trm_DataOutPhase0, /* phase:0 */
+ trm_DataInPhase0, /* phase:1 */
+ trm_Nop, /* phase:2 */
+ trm_StatusPhase0, /* phase:3 */
+ trm_Nop, /* phase:4 */
+ trm_Nop, /* phase:5 */
+ trm_MsgOutPhase0, /* phase:6 */
+ trm_MsgInPhase0, /* phase:7 */
+};
+
+/*
+ * ------------------------------------------------------------
+ *
+ * stateV = (void *) trm_SCSI_phase1[phase]
+ *
+ * ------------------------------------------------------------
+ */
+static void *trm_SCSI_phase1[8] = {
+ trm_DataOutPhase1, /* phase:0 */
+ trm_DataInPhase1, /* phase:1 */
+ trm_CommandPhase1, /* phase:2 */
+ trm_StatusPhase1, /* phase:3 */
+ trm_Nop, /* phase:4 */
+ trm_Nop, /* phase:5 */
+ trm_MsgOutPhase1, /* phase:6 */
+ trm_MsgInPhase1, /* phase:7 */
+};
+
+
+struct trm_adapter_nvram trm_eepromBuf[TRM_MAX_ADAPTER_NUM];
+/*
+ *Fast20: 000 50ns, 20.0 Mbytes/s
+ * 001 75ns, 13.3 Mbytes/s
+ * 010 100ns, 10.0 Mbytes/s
+ * 011 125ns, 8.0 Mbytes/s
+ * 100 150ns, 6.6 Mbytes/s
+ * 101 175ns, 5.7 Mbytes/s
+ * 110 200ns, 5.0 Mbytes/s
+ * 111 250ns, 4.0 Mbytes/s
+ *
+ *Fast40: 000 25ns, 40.0 Mbytes/s
+ * 001 50ns, 20.0 Mbytes/s
+ * 010 75ns, 13.3 Mbytes/s
+ * 011 100ns, 10.0 Mbytes/s
+ * 100 125ns, 8.0 Mbytes/s
+ * 101 150ns, 6.6 Mbytes/s
+ * 110 175ns, 5.7 Mbytes/s
+ * 111 200ns, 5.0 Mbytes/s
+ */
+
+/*
+ * real period:
+ */
+u_int8_t trm_clock_period[8] = {
+ /* nanosecond divided by 4 */
+ 12, /* 48 ns 20 MB/sec */
+ 18, /* 72 ns 13.3 MB/sec */
+ 25, /* 100 ns 10.0 MB/sec */
+ 31, /* 124 ns 8.0 MB/sec */
+ 37, /* 148 ns 6.6 MB/sec */
+ 43, /* 172 ns 5.7 MB/sec */
+ 50, /* 200 ns 5.0 MB/sec */
+ 62 /* 248 ns 4.0 MB/sec */
+};
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_GetFreeSRB
+ * Purpose : Get the first free SRB
+ * Inputs :
+ * Return : NULL or a free SCSI Request block
+ * ------------------------------------------------------------
+ */
+struct trm_scsi_req_q *
+trm_GetFreeSRB(struct trm_softc *sc)
+{
+ struct trm_scsi_req_q *pSRB;
+
+ /* ASSUME we are called from inside a splbio()/splx() region */
+
+ pSRB = TAILQ_FIRST(&sc->freeSRB);
+
+ if (pSRB != NULL)
+ TAILQ_REMOVE(&sc->freeSRB, pSRB, link);
+
+#ifdef TRM_DEBUG0
+ printf("%s: trm_GetFreeSRB. pSRB = %p, next pSRB = %p\n",
+ sc->sc_device.dv_xname, pSRB, TAILQ_FIRST(&sc->freeSRB));
+#endif
+
+ return pSRB;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_RewaitSRB
+ * Purpose : Q back to pending Q
+ * Inputs : struct trm_dcb * -
+ * struct trm_scsi_req_q * -
+ * ------------------------------------------------------------
+ */
+void
+trm_RewaitSRB(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
+{
+ int intflag;
+
+ intflag = splbio();
+
+ if ((pSRB->SRBFlag & TRM_ON_WAITING_SRB) != 0) {
+ pSRB->SRBFlag &= ~TRM_ON_WAITING_SRB;
+ TAILQ_REMOVE(&sc->waitingSRB, pSRB, link);
+ }
+
+ if ((pSRB->SRBFlag & TRM_ON_GOING_SRB) != 0) {
+ pSRB->SRBFlag &= ~TRM_ON_GOING_SRB;
+ TAILQ_REMOVE(&sc->goingSRB, pSRB, link);
+ }
+
+ pSRB->SRBState = TRM_READY;
+ pSRB->TargetStatus = SCSI_OK;
+ pSRB->AdaptStatus = TRM_STATUS_GOOD;
+
+ pSRB->SRBFlag |= TRM_ON_WAITING_SRB;
+ TAILQ_INSERT_HEAD(&sc->waitingSRB, pSRB, link);
+
+ splx(intflag);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_StartWaitingSRB
+ * Purpose : If there is no active DCB then run robin through
+ * the DCB's to find the next waiting SRB
+ * and move it to the going list.
+ * Inputs : struct trm_softc * -
+ * ------------------------------------------------------------
+ */
+void
+trm_StartWaitingSRB(struct trm_softc *sc)
+{
+ struct trm_scsi_req_q *pSRB;
+ int intflag;
+
+ intflag = splbio();
+
+ if ((sc->pActiveDCB != NULL) ||
+ (TAILQ_EMPTY(&sc->waitingSRB)) ||
+ (sc->sc_Flag & (RESET_DETECT | RESET_DONE | RESET_DEV)) != 0)
+ return;
+
+ TAILQ_FOREACH(pSRB, &sc->waitingSRB, link) {
+ if (trm_StartSRB(sc, pSRB) == 0) {
+ pSRB->SRBFlag &= ~TRM_ON_WAITING_SRB;
+ TAILQ_REMOVE(&sc->waitingSRB, pSRB, link);
+ pSRB->SRBFlag |= TRM_ON_GOING_SRB;
+ TAILQ_INSERT_TAIL(&sc->goingSRB, pSRB, link);
+ break;
+ }
+ }
+
+ splx(intflag);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_scsi_cmd
+ * Purpose : enqueues a SCSI command
+ * Inputs :
+ * Call By : GENERIC SCSI driver
+ * ------------------------------------------------------------
+ */
+int
+trm_scsi_cmd(struct scsi_xfer *xs)
+{
+ struct trm_scsi_req_q *pSRB;
+ bus_space_handle_t ioh;
+ struct trm_softc *sc;
+ bus_space_tag_t iot;
+ struct trm_dcb *pDCB;
+ u_int8_t target, lun;
+ int i, error, intflag, xferflags;
+
+ target = xs->sc_link->target;
+ lun = xs->sc_link->lun;
+
+ sc = (struct trm_softc *)xs->sc_link->adapter_softc;
+ ioh = sc->sc_iohandle;
+ iot = sc->sc_iotag;
+
+#ifdef TRM_DEBUG0
+ if ((xs->flags & SCSI_POLL) != 0)
+ printf("%s: trm_scsi_cmd. sc = %p, xs = %p, targ/lun = %d/%d opcode = 0x%02x\n",
+ sc->sc_device.dv_xname, sc, xs, target, lun, xs->cmd->opcode);
+#endif
+
+ if (target >= TRM_MAX_TARGETS) {
+ printf("%s: target=%d >= %d\n",
+ sc->sc_device.dv_xname, target, TRM_MAX_TARGETS);
+ xs->error = XS_DRIVER_STUFFUP;
+ return COMPLETE;
+ }
+ if (lun >= TRM_MAX_LUNS) {
+ printf("%s: lun=%d >= %d\n",
+ sc->sc_device.dv_xname, lun, TRM_MAX_LUNS);
+ xs->error = XS_DRIVER_STUFFUP;
+ return COMPLETE;
+ }
+
+ pDCB = sc->pDCB[target][lun];
+ if (pDCB == NULL) {
+ /* Removed as a result of INQUIRY proving no device present */
+ xs->error = XS_DRIVER_STUFFUP;
+ return COMPLETE;
+ }
+
+ xferflags = xs->flags;
+ if (xferflags & SCSI_RESET) {
+#ifdef TRM_DEBUG0
+ printf("%s: trm_reset\n", sc->sc_device.dv_xname);
+#endif
+ trm_reset(sc);
+ xs->error = XS_NOERROR;
+ return COMPLETE;
+ }
+
+ if (xferflags & ITSDONE) {
+#ifdef TRM_DEBUG0
+ printf("%s: Is it done?\n", sc->sc_device.dv_xname);
+#endif
+ xs->flags &= ~ITSDONE;
+ }
+
+ xs->error = XS_NOERROR;
+ xs->status = SCSI_OK;
+ xs->resid = 0;
+
+ intflag = splbio();
+
+ pSRB = trm_GetFreeSRB(sc);
+
+ if (pSRB == NULL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ splx(intflag);
+ return TRY_AGAIN_LATER;
+ }
+
+ /*
+ * BuildSRB(pSRB,pDCB);
+ */
+ if (xs->datalen != 0) {
+#ifdef TRM_DEBUG0
+ printf("%s: xs->datalen=%x\n", sc->sc_device.dv_xname,
+ (u_int32_t)xs->datalen);
+ printf("%s: sc->sc_dmatag=0x%x\n", sc->sc_device.dv_xname,
+ (u_int32_t)sc->sc_dmatag);
+ printf("%s: pSRB->dmamapxfer=0x%x\n", sc->sc_device.dv_xname,
+ (u_int32_t)pSRB->dmamapxfer);
+ printf("%s: xs->data=0x%x\n", sc->sc_device.dv_xname,
+ (u_int32_t)xs->data);
+#endif
+ if ((error = bus_dmamap_load(sc->sc_dmatag, pSRB->dmamapxfer,
+ xs->data, xs->datalen, NULL,
+ (xferflags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
+ BUS_DMA_WAITOK)) != 0) {
+ printf("%s: DMA transfer map unable to load, error = %d\n"
+ , sc->sc_device.dv_xname, error);
+ xs->error = XS_DRIVER_STUFFUP;
+ /*
+ * free SRB
+ */
+ TAILQ_INSERT_HEAD(&sc->freeSRB, pSRB, link);
+ splx(intflag);
+ return COMPLETE;
+ }
+
+ bus_dmamap_sync(sc->sc_dmatag, pSRB->dmamapxfer,
+ 0, pSRB->dmamapxfer->dm_mapsize,
+ (xferflags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Set up the scatter gather list
+ */
+ for (i = 0; i < pSRB->dmamapxfer->dm_nsegs; i++) {
+ pSRB->SegmentX[i].address = pSRB->dmamapxfer->dm_segs[i].ds_addr;
+ pSRB->SegmentX[i].length = pSRB->dmamapxfer->dm_segs[i].ds_len;
+ }
+ pSRB->SRBTotalXferLength = xs->datalen;
+ pSRB->SRBSGCount = pSRB->dmamapxfer->dm_nsegs;
+ }
+
+ pSRB->pSRBDCB = pDCB;
+ pSRB->xs = xs;
+ pSRB->ScsiCmdLen = xs->cmdlen;
+
+ memcpy(pSRB->CmdBlock, xs->cmd, xs->cmdlen);
+
+ splx (intflag);
+
+ timeout_set(&xs->stimeout, trm_timeout, pSRB);
+
+ intflag = splbio();
+
+ pSRB->SRBFlag |= TRM_ON_WAITING_SRB;
+ TAILQ_INSERT_TAIL(&sc->waitingSRB, pSRB, link);
+ trm_StartWaitingSRB(sc);
+
+ if ((xferflags & SCSI_POLL) == 0) {
+ timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000);
+ splx(intflag);
+ return SUCCESSFULLY_QUEUED;
+ }
+
+ while ((--xs->timeout > 0) && ((xs->flags & ITSDONE) == 0)) {
+ trm_Interrupt(sc);
+ DELAY(1000);
+ }
+
+ if (xs->timeout == 0)
+ trm_timeout(pSRB);
+
+ splx(intflag);
+ return COMPLETE;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_ResetAllDevParam
+ * Purpose :
+ * Inputs : struct trm_softc *
+ * ------------------------------------------------------------
+ */
+void
+trm_ResetAllDevParam(struct trm_softc *sc)
+{
+ struct trm_adapter_nvram *pEEpromBuf;
+ int target, quirks;
+
+ pEEpromBuf = &trm_eepromBuf[sc->sc_AdapterUnit];
+
+ for (target = 0; target < TRM_MAX_TARGETS; target++) {
+ if (target == sc->sc_AdaptSCSIID)
+ continue;
+
+ if ((sc->pDCB[target][0]->DCBFlag & TRM_QUIRKS_VALID) == 0)
+ quirks = SDEV_NOWIDE | SDEV_NOSYNC | SDEV_NOTAGS;
+ else
+ quirks = sc->pDCB[target][0]->sc_link->quirks;
+
+ trm_ResetDevParam(sc, sc->pDCB[target][0], quirks);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_ResetDevParam
+ * Purpose :
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_ResetDevParam(struct trm_softc *sc, struct trm_dcb *pDCB, u_int8_t quirks)
+{
+ struct trm_adapter_nvram *pEEpromBuf = &trm_eepromBuf[sc->sc_AdapterUnit];
+ u_int8_t PeriodIndex;
+ const int target = pDCB->target;
+
+ pDCB->DCBFlag &= TRM_QUIRKS_VALID;
+ pDCB->DCBFlag |= (TRM_WIDE_NEGO_ENABLE | TRM_SYNC_NEGO_ENABLE);
+
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+ pDCB->MaxNegoPeriod = 0;
+
+ pDCB->DevMode = pEEpromBuf->NvramTarget[target].NvmTarCfg0;
+
+ pDCB->IdentifyMsg = MSG_IDENTIFY(pDCB->lun, ((pDCB->DevMode & TRM_DISCONNECT) != 0));
+
+ if (((quirks & SDEV_NOWIDE) == 0) &&
+ (pDCB->DevMode & TRM_WIDE) &&
+ ((sc->sc_config & HCC_WIDE_CARD) != 0))
+ pDCB->DCBFlag |= TRM_WIDE_NEGO_16BIT;
+
+ if (((quirks & SDEV_NOSYNC) == 0) &&
+ ((pDCB->DevMode & TRM_SYNC) != 0)) {
+ PeriodIndex = pEEpromBuf->NvramTarget[target].NvmTarPeriod & 0x07;
+ pDCB->MaxNegoPeriod = trm_clock_period[PeriodIndex];
+ }
+
+ if (((quirks & SDEV_NOTAGS) == 0) &&
+ ((pDCB->DevMode & TRM_TAG_QUEUING) != 0) &&
+ ((pDCB->DevMode & TRM_DISCONNECT) != 0))
+ /* TODO XXXX: Every device(lun) gets to queue TagMaxNum commands? */
+ pDCB->DCBFlag |= TRM_USE_TAG_QUEUING;
+
+ trm_SetXferParams(sc, pDCB, 0);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_RecoverSRB
+ * Purpose : Moves all SRBs from Going to Waiting for all the Link DCBs
+ * Inputs : struct trm_softc * -
+ * ------------------------------------------------------------
+ */
+void
+trm_RecoverSRB(struct trm_softc *sc)
+{
+ struct trm_scsi_req_q *pSRB;
+
+ /* ASSUME we are inside splbio()/splx() */
+
+ while ((pSRB = TAILQ_FIRST(&sc->goingSRB)) != NULL) {
+ pSRB->SRBFlag &= ~TRM_ON_GOING_SRB;
+ TAILQ_REMOVE(&sc->goingSRB, pSRB, link);
+ pSRB->SRBFlag |= TRM_ON_WAITING_SRB;
+ TAILQ_INSERT_HEAD(&sc->waitingSRB, pSRB, link);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_reset
+ * Purpose : perform a hard reset on the SCSI bus (and TRM_S1040 chip).
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_reset (struct trm_softc *sc)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ int i, intflag;
+
+#ifdef TRM_DEBUG0
+ printf("%s: trm_reset", sc->sc_device.dv_xname);
+#endif
+
+ intflag = splbio();
+
+ bus_space_write_1(iot, ioh, TRM_S1040_DMA_INTEN, 0);
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_INTEN, 0);
+
+ trm_ResetSCSIBus(sc);
+ for (i = 0; i < 500; i++)
+ DELAY(1000);
+
+ /*
+ * Enable all SCSI interrupts except EN_SCAM
+ */
+ bus_space_write_1(iot, ioh,
+ TRM_S1040_SCSI_INTEN,
+ (EN_SELECT | EN_SELTIMEOUT | EN_DISCONNECT | EN_RESELECTED |
+ EN_SCSIRESET | EN_BUSSERVICE | EN_CMDDONE));
+ /*
+ * Enable DMA interrupt
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_DMA_INTEN, EN_SCSIINTR);
+ /*
+ * Clear DMA FIFO
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_DMA_CONTROL, CLRXFIFO);
+ /*
+ * Clear SCSI FIFO
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
+
+ trm_ResetAllDevParam(sc);
+ trm_GoingSRB_Done(sc);
+ sc->pActiveDCB = NULL;
+
+ /*
+ * RESET_DETECT, RESET_DONE, RESET_DEV
+ */
+ sc->sc_Flag = 0;
+ trm_StartWaitingSRB(sc);
+
+ splx(intflag);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_timeout
+ * Purpose : Prints a timeout message and aborts the timed out SCSI request
+ * Inputs : void * - A struct trm_scsi_req_q * structure pointer
+ * ------------------------------------------------------------
+ */
+void
+trm_timeout(void *arg1)
+{
+ struct trm_scsi_req_q *pSRB;
+ struct scsi_xfer *xs;
+ struct trm_softc *sc;
+
+ pSRB = (struct trm_scsi_req_q *)arg1;
+ xs = pSRB->xs;
+
+ if (xs != NULL) {
+ sc = xs->sc_link->adapter_softc;
+ sc_print_addr(xs->sc_link);
+ printf("%s: SCSI OpCode 0x%02x for target %d lun %d timed out\n",
+ sc->sc_device.dv_xname, xs->cmd->opcode,
+ xs->sc_link->target, xs->sc_link->lun);
+ pSRB->SRBFlag |= TRM_SCSI_TIMED_OUT;
+ trm_FinishSRB(sc, pSRB);
+ trm_StartWaitingSRB(sc);
+ }
+#ifdef TRM_DEBUG0
+ else
+ printf("%s: trm_timeout called with xs == NULL\n",
+ sc->sc_device.dv_xname);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_StartSRB
+ * Purpose : Send the commands in the SRB to the device
+ * Inputs : struct trm_softc * -
+ * struct trm_scsi_req_q * -
+ * Return : 0 - SCSI processor is unoccupied
+ * 1 - SCSI processor is occupied with an SRB
+ * ------------------------------------------------------------
+ */
+int
+trm_StartSRB(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ struct trm_dcb *pDCB = pSRB->pSRBDCB;
+ u_int32_t tag_mask;
+ u_int8_t tag_id, scsicommand;
+
+#ifdef TRM_DEBUG0
+ printf("%s: trm_StartSRB. sc = %p, pDCB = %p, pSRB = %p\n",
+ sc->sc_device.dv_xname, sc, pDCB, pSRB);
+#endif
+ if ((pDCB->DCBFlag & TRM_QUEUE_FULL) != 0)
+ return 1;
+
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_HOSTID, sc->sc_AdaptSCSIID);
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_TARGETID, pDCB->target);
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_SYNC, pDCB->SyncPeriod);
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_OFFSET, pDCB->SyncOffset);
+
+ if ((sc->pDCB[pDCB->target][0]->sc_link != NULL) &&
+ ((sc->pDCB[pDCB->target][0]->DCBFlag & TRM_QUIRKS_VALID) == 0)) {
+ sc->pDCB[pDCB->target][0]->DCBFlag |= TRM_QUIRKS_VALID;
+ trm_ResetDevParam(sc, sc->pDCB[pDCB->target][0], sc->pDCB[pDCB->target][0]->sc_link->quirks);
+ }
+
+ /*
+ * initial phase
+ */
+
+ pSRB->ScsiPhase = PH_BUS_FREE;
+
+ /*
+ * Flush FIFO
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
+
+ sc->MsgCnt = 1;
+ sc->MsgBuf[0] = pDCB->IdentifyMsg;
+ if (((pSRB->xs->flags & SCSI_POLL) != 0) ||
+ (pSRB->CmdBlock[0] == INQUIRY) ||
+ (pSRB->CmdBlock[0] == REQUEST_SENSE))
+ sc->MsgBuf[0] &= ~MSG_IDENTIFY_DISCFLAG;
+
+ scsicommand = SCMD_SEL_ATN;
+ pSRB->SRBState = TRM_START;
+
+ if ((pDCB->DCBFlag & (TRM_WIDE_NEGO_ENABLE | TRM_SYNC_NEGO_ENABLE)) != 0) {
+ scsicommand = SCMD_SEL_ATNSTOP;
+ pSRB->SRBState = TRM_MSGOUT;
+
+ } else if (((sc->MsgBuf[0] & MSG_IDENTIFY_DISCFLAG) != 0) &&
+ ((pDCB->DCBFlag & TRM_USE_TAG_QUEUING) != 0)) {
+
+ if (pSRB->TagNumber == TRM_NO_TAG) {
+ for (tag_id=1, tag_mask=2; tag_id < 32; tag_id++, tag_mask <<= 1)
+ if ((tag_mask & pDCB->TagMask) == 0) {
+ pDCB->TagMask |= tag_mask;
+ pSRB->TagNumber = tag_id;
+ break;
+ }
+
+ if (tag_id >= 32) {
+ pDCB->DCBFlag |= TRM_QUEUE_FULL;
+ sc->MsgCnt = 0;
+ return 1;
+ }
+ }
+
+ /* TODO XXXX: Should send ORDERED_Q_TAG if metadata (non-block) i/o!? */
+ sc->MsgBuf[sc->MsgCnt++] = MSG_SIMPLE_Q_TAG;
+ sc->MsgBuf[sc->MsgCnt++] = pSRB->TagNumber;
+
+ scsicommand = SCMD_SEL_ATN3;
+ }
+
+ if ((bus_space_read_2(iot, ioh, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) != 0) {
+ /*
+ * return 1 :
+ * current interrupt status is interrupt disreenable
+ * It's said that SCSI processor has more then one SRB it needs
+ * to do, SCSI processor has been occupied by one SRB.
+ */
+ pSRB->SRBState = TRM_READY;
+ return 1;
+ }
+
+ /*
+ * return 0 :
+ * current interrupt status is interrupt enable
+ * It's said that SCSI processor is unoccupied
+ */
+ pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */
+ sc->pActiveDCB = pDCB;
+ pDCB->pActiveSRB = pSRB;
+
+ if (sc->MsgCnt > 0) {
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_FIFO, sc->MsgBuf[0]);
+ if (sc->MsgCnt > 1) {
+ DELAY(30);
+ bus_space_write_multi_1(iot, ioh, TRM_S1040_SCSI_FIFO, &sc->MsgBuf[1], sc->MsgCnt - 1);
+ }
+ sc->MsgCnt = 0;
+ }
+
+ /*
+ * it's important for atn stop
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH | DO_HWRESELECT);
+ /*
+ * SCSI command
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, scsicommand);
+
+ return 0;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_Interrupt
+ * Purpose : Catch an interrupt from the adapter
+ * Process pending device interrupts.
+ * Inputs : void * - struct trm_softc * strucutre pointer
+ * ------------------------------------------------------------
+ */
+int
+trm_Interrupt(void *vsc)
+{
+ void (*stateV)(struct trm_softc *, struct trm_scsi_req_q *, u_int8_t *);
+ struct trm_scsi_req_q *pSRB;
+ bus_space_handle_t ioh;
+ struct trm_softc *sc = (struct trm_softc *)vsc;
+ bus_space_tag_t iot;
+ u_int16_t phase;
+ u_int8_t scsi_status, scsi_intstatus;
+ int intflag;
+
+ intflag = splbio();
+
+ if (sc == NULL) {
+ splx(intflag);
+ return 0;
+ }
+
+ ioh = sc->sc_iohandle;
+ iot = sc->sc_iotag;
+
+ scsi_status = bus_space_read_2(iot, ioh, TRM_S1040_SCSI_STATUS);
+ if (!(scsi_status & SCSIINTERRUPT)) {
+ splx(intflag);
+ return 0;
+ }
+ scsi_intstatus = bus_space_read_1(iot, ioh, TRM_S1040_SCSI_INTSTATUS);
+
+#ifdef TRM_DEBUG0
+ printf("%s: trm_interrupt - scsi_status=0x%02x, scsi_intstatus=0x%02x\n",
+ sc->sc_device.dv_xname, scsi_status, scsi_intstatus);
+#endif
+ if ((scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) != 0)
+ trm_Disconnect(sc);
+
+ else if ((scsi_intstatus & INT_RESELECTED) != 0)
+ trm_Reselect(sc);
+
+ else if ((scsi_intstatus & INT_SCSIRESET) != 0)
+ trm_ScsiRstDetect(sc);
+
+ else if ((sc->pActiveDCB != NULL) && ((scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) != 0)) {
+ pSRB = sc->pActiveDCB->pActiveSRB;
+ /*
+ * software sequential machine
+ */
+ phase = (u_int16_t) pSRB->ScsiPhase; /* phase: */
+ /*
+ * 62037 or 62137
+ * call trm_SCSI_phase0[]... "phase entry"
+ * handle every phase before start transfer
+ */
+ stateV = trm_SCSI_phase0[phase];
+ stateV(sc, pSRB, &scsi_status);
+ /*
+ * if any exception occured
+ * scsi_status will be modified to bus free phase
+ * new scsi_status transfer out from previous stateV
+ */
+ /*
+ * phase:0,1,2,3,4,5,6,7
+ */
+ pSRB->ScsiPhase = scsi_status & PHASEMASK;
+ phase = (u_int16_t) scsi_status & PHASEMASK;
+ /*
+ * call trm_SCSI_phase1[]... "phase entry"
+ * handle every phase do transfer
+ */
+ stateV = trm_SCSI_phase1[phase];
+ stateV(sc, pSRB, &scsi_status);
+
+ } else {
+ splx(intflag);
+ return 0;
+ }
+
+ splx(intflag);
+ return 1;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_MsgOutPhase0
+ * Purpose : Check the state machine before sending a message out
+ * Inputs : struct trm_softc * -
+ * struct trm_scsi_req_q * -
+ * u_int8_t * - scsi status, set to PH_BUS_FREE if not ready
+ * ------------------------------------------------------------
+ */
+void
+trm_MsgOutPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ switch (pSRB->SRBState) {
+ case TRM_UNEXPECT_RESEL:
+ case TRM_ABORT_SENT:
+ *pscsi_status = PH_BUS_FREE; /* initial phase */
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_MsgOutPhase1
+ * Purpose : Write the message out to the bus
+ * Inputs : struct trm_softc * -
+ * struct trm_scsi_req_q * -
+ * u_int8_t * - unused
+ * ------------------------------------------------------------
+ */
+void
+trm_MsgOutPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ struct trm_dcb *pDCB = sc->pActiveDCB;
+
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
+
+ if ((pDCB->DCBFlag & TRM_WIDE_NEGO_ENABLE) != 0) {
+ /*
+ * WIDE DATA TRANSFER REQUEST code (03h)
+ */
+ pDCB->DCBFlag &= ~TRM_WIDE_NEGO_ENABLE;
+ pDCB->DCBFlag |= TRM_DOING_WIDE_NEGO;
+
+ sc->MsgBuf[0] = pDCB->IdentifyMsg & ~MSG_IDENTIFY_DISCFLAG;
+ sc->MsgBuf[1] = MSG_EXTENDED;
+ sc->MsgBuf[2] = MSG_EXT_WDTR_LEN;
+ sc->MsgBuf[3] = MSG_EXT_WDTR;
+
+ if ((pDCB->DCBFlag & TRM_WIDE_NEGO_16BIT) == 0)
+ sc->MsgBuf[4] = MSG_EXT_WDTR_BUS_8_BIT;
+ else
+ sc->MsgBuf[4] = MSG_EXT_WDTR_BUS_16_BIT;
+
+ sc->MsgCnt = 5;
+
+ } else if ((pDCB->DCBFlag & TRM_SYNC_NEGO_ENABLE) != 0) {
+
+ pDCB->DCBFlag &= ~TRM_SYNC_NEGO_ENABLE;
+ pDCB->DCBFlag |= TRM_DOING_SYNC_NEGO;
+
+ sc->MsgCnt = 0;
+
+ if ((pDCB->DCBFlag & TRM_WIDE_NEGO_DONE) == 0)
+ sc->MsgBuf[sc->MsgCnt++] = pDCB->IdentifyMsg & ~MSG_IDENTIFY_DISCFLAG;
+
+ sc->MsgBuf[sc->MsgCnt++] = MSG_EXTENDED;
+ sc->MsgBuf[sc->MsgCnt++] = MSG_EXT_SDTR_LEN;
+ sc->MsgBuf[sc->MsgCnt++] = MSG_EXT_SDTR;
+ sc->MsgBuf[sc->MsgCnt++] = pDCB->MaxNegoPeriod;
+
+ if (pDCB->MaxNegoPeriod > 0)
+ sc->MsgBuf[sc->MsgCnt++] = TRM_MAX_SYNC_OFFSET;
+ else
+ sc->MsgBuf[sc->MsgCnt++] = 0;
+ }
+
+ if (sc->MsgCnt > 0) {
+ bus_space_write_multi_1(iot, ioh, TRM_S1040_SCSI_FIFO, &sc->MsgBuf[0], sc->MsgCnt);
+ if (sc->MsgBuf[0] == MSG_ABORT)
+ pSRB->SRBState = TRM_ABORT_SENT;
+ sc->MsgCnt = 0;
+ }
+ /*
+ * it's important for atn stop
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+ /*
+ * Transfer information out
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_CommandPhase1
+ * Purpose : Send commands to bus
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_CommandPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRATN | DO_CLRFIFO);
+
+ bus_space_write_multi_1(iot, ioh, TRM_S1040_SCSI_FIFO, &pSRB->CmdBlock[0], pSRB->ScsiCmdLen);
+
+ pSRB->SRBState = TRM_COMMAND;
+ /*
+ * it's important for atn stop
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+ /*
+ * Transfer information out
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_DataOutPhase0
+ * Purpose : Ready for Data Out, clear FIFO
+ * Inputs : u_int8_t * - SCSI status, used but not set
+ * ------------------------------------------------------------
+ */
+void
+trm_DataOutPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ struct SGentry *pseg;
+ struct trm_dcb *pDCB;
+ u_int32_t dLeftCounter, TempSRBXferredLength;
+ u_int16_t scsi_status;
+ u_int8_t TempDMAstatus, SGIndexTemp;
+
+ dLeftCounter = 0;
+
+ pDCB = pSRB->pSRBDCB;
+ scsi_status = *pscsi_status;
+
+ if (pSRB->SRBState != TRM_XFERPAD) {
+ if ((scsi_status & PARITYERROR) != 0)
+ pSRB->SRBFlag |= TRM_PARITY_ERROR;
+ if ((scsi_status & SCSIXFERDONE) == 0) {
+ /*
+ * when data transfer from DMA FIFO to SCSI FIFO
+ * if there was some data left in SCSI FIFO
+ */
+ dLeftCounter = (u_int32_t)(bus_space_read_1(
+ iot, ioh, TRM_S1040_SCSI_FIFOCNT) & 0x1F);
+ if (pDCB->SyncPeriod & WIDE_SYNC) {
+ /*
+ * if WIDE scsi SCSI FIFOCNT unit is word
+ * so need to * 2
+ */
+ dLeftCounter <<= 1;
+ }
+ }
+ /*
+ * caculate all the residue data that not yet tranfered
+ * SCSI transfer counter + left in SCSI FIFO data
+ *
+ * .....TRM_S1040_SCSI_COUNTER (24bits)
+ * The counter always decrement by one for every SCSI byte
+ * transfer.
+ * .....TRM_S1040_SCSI_FIFOCNT ( 5bits)
+ * The counter is SCSI FIFO offset counter
+ */
+ dLeftCounter += bus_space_read_4(iot, ioh,
+ TRM_S1040_SCSI_COUNTER);
+ if (dLeftCounter == 1) {
+ dLeftCounter = 0;
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL,
+ DO_CLRFIFO);
+ }
+ if (dLeftCounter == 0 ||
+ (scsi_status & SCSIXFERCNT_2_ZERO) != 0) {
+ TempDMAstatus = bus_space_read_1(iot,
+ ioh, TRM_S1040_DMA_STATUS);
+ while ((TempDMAstatus & DMAXFERCOMP) == 0) {
+ TempDMAstatus = bus_space_read_1(iot,
+ ioh, TRM_S1040_DMA_STATUS);
+ }
+ pSRB->SRBTotalXferLength = 0;
+ } else {
+ /*
+ * Update SG list
+ */
+ /*
+ * if transfer not yet complete
+ * there were some data residue in SCSI FIFO or
+ * SCSI transfer counter not empty
+ */
+ if (pSRB->SRBTotalXferLength != dLeftCounter) {
+ /*
+ * data that had transferred length
+ */
+ TempSRBXferredLength = pSRB->SRBTotalXferLength
+ - dLeftCounter;
+ /*
+ * next time to be transferred length
+ */
+ pSRB->SRBTotalXferLength = dLeftCounter;
+ /*
+ * parsing from last time disconnect SRBSGIndex
+ */
+ pseg = &pSRB->SegmentX[pSRB->SRBSGIndex];
+ for (SGIndexTemp = pSRB->SRBSGIndex;
+ SGIndexTemp < pSRB->SRBSGCount;
+ SGIndexTemp++) {
+ /*
+ * find last time which SG transfer be
+ * disconnect
+ */
+ if (TempSRBXferredLength >= pseg->length)
+ TempSRBXferredLength -= pseg->length;
+ else {
+ /*
+ * update last time disconnected
+ * SG list
+ */
+ /*
+ * residue data length
+ */
+ pseg->length -=
+ TempSRBXferredLength;
+ /*
+ * residue data pointer
+ */
+ pseg->address +=
+ TempSRBXferredLength;
+ pSRB->SRBSGIndex = SGIndexTemp;
+ break;
+ }
+ pseg++;
+ }
+ }
+ }
+ }
+ bus_space_write_1(iot, ioh, TRM_S1040_DMA_CONTROL, STOPDMAXFER);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_DataOutPhase1
+ * Purpose : Transfers data out, calls trm_DataIO_transfer
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_DataOutPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ trm_DataIO_transfer(sc, pSRB, XFERDATAOUT);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_DataInPhase0
+ * Purpose : Prepare for reading data in from bus
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_DataInPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ struct SGentry *pseg;
+ u_int32_t TempSRBXferredLength, dLeftCounter;
+ u_int16_t scsi_status;
+ u_int8_t SGIndexTemp;
+
+ dLeftCounter = 0;
+
+ scsi_status = *pscsi_status;
+ if (pSRB->SRBState != TRM_XFERPAD) {
+ if ((scsi_status & PARITYERROR) != 0)
+ pSRB->SRBFlag |= TRM_PARITY_ERROR;
+ dLeftCounter += bus_space_read_4(iot, ioh,
+ TRM_S1040_SCSI_COUNTER);
+ if (dLeftCounter == 0 ||
+ (scsi_status & SCSIXFERCNT_2_ZERO) != 0) {
+ while ((bus_space_read_1(iot, ioh, TRM_S1040_DMA_STATUS) & DMAXFERCOMP) == 0)
+ ;
+ pSRB->SRBTotalXferLength = 0;
+ } else {
+ /*
+ * phase changed
+ *
+ * parsing the case:
+ * when a transfer not yet complete
+ * but be disconnected by uper layer
+ * if transfer not yet complete
+ * there were some data residue in SCSI FIFO or
+ * SCSI transfer counter not empty
+ */
+ if (pSRB->SRBTotalXferLength != dLeftCounter) {
+ /*
+ * data that had transferred length
+ */
+ TempSRBXferredLength = pSRB->SRBTotalXferLength
+ - dLeftCounter;
+ /*
+ * next time to be transferred length
+ */
+ pSRB->SRBTotalXferLength = dLeftCounter;
+ /*
+ * parsing from last time disconnect SRBSGIndex
+ */
+ pseg = &pSRB->SegmentX[pSRB->SRBSGIndex];
+ for (SGIndexTemp = pSRB->SRBSGIndex;
+ SGIndexTemp < pSRB->SRBSGCount;
+ SGIndexTemp++) {
+ /*
+ * find last time which SG transfer be
+ * disconnect
+ */
+ if (TempSRBXferredLength >=
+ pseg->length) {
+ TempSRBXferredLength -= pseg->length;
+ } else {
+ /*
+ * update last time disconnected
+ * SG list
+ *
+ * residue data length
+ */
+ pseg->length -= TempSRBXferredLength;
+ /*
+ * residue data pointer
+ */
+ pseg->address += TempSRBXferredLength;
+ pSRB->SRBSGIndex = SGIndexTemp;
+ break;
+ }
+ pseg++;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_DataInPhase1
+ * Purpose : Transfer data in from bus, calls trm_DataIO_transfer
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_DataInPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ trm_DataIO_transfer(sc, pSRB, XFERDATAIN);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_DataIO_transfer
+ * Purpose :
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_DataIO_transfer(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int16_t ioDir)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ struct trm_dcb *pDCB = pSRB->pSRBDCB;
+ u_int8_t bval;
+
+ if (pSRB->SRBSGIndex < pSRB->SRBSGCount) {
+ if (pSRB->SRBTotalXferLength != 0) {
+ /*
+ * load what physical address of Scatter/Gather list
+ * table want to be transfer
+ */
+ pSRB->SRBState = TRM_DATA_XFER;
+ bus_space_write_4(iot, ioh, TRM_S1040_DMA_XHIGHADDR, 0);
+ bus_space_write_4(iot, ioh,
+ TRM_S1040_DMA_XLOWADDR, (pSRB->SRBSGPhyAddr +
+ ((u_int32_t)pSRB->SRBSGIndex << 3)));
+ /*
+ * load how many bytes in the Scatter/Gather list table
+ */
+ bus_space_write_4(iot, ioh, TRM_S1040_DMA_XCNT,
+ ((u_int32_t)(pSRB->SRBSGCount -
+ pSRB->SRBSGIndex) << 3));
+ /*
+ * load total transfer length (24bits,
+ * pSRB->SRBTotalXferLength) max value 16Mbyte
+ */
+ bus_space_write_4(iot, ioh,
+ TRM_S1040_SCSI_COUNTER, pSRB->SRBTotalXferLength);
+ /*
+ * Start DMA transfer
+ */
+ bus_space_write_2(iot,ioh,TRM_S1040_DMA_COMMAND, ioDir);
+ /* bus_space_write_2(iot, ioh,
+ TRM_S1040_DMA_CONTROL, STARTDMAXFER);*/
+ /*
+ * Set the transfer bus and direction
+ */
+ bval = ioDir == XFERDATAOUT ? SCMD_DMA_OUT :SCMD_DMA_IN;
+ } else {
+ /*
+ * xfer pad
+ */
+ if (pSRB->SRBSGCount)
+ pSRB->AdaptStatus = TRM_OVER_UNDER_RUN;
+
+ if (pDCB->SyncPeriod & WIDE_SYNC) {
+ bus_space_write_4(iot, ioh,
+ TRM_S1040_SCSI_COUNTER, 2);
+ } else {
+ bus_space_write_4(iot, ioh,
+ TRM_S1040_SCSI_COUNTER, 1);
+ }
+
+ if (ioDir == XFERDATAOUT) {
+ bus_space_write_2(iot,
+ ioh, TRM_S1040_SCSI_FIFO, 0);
+ } else {
+ bus_space_read_2(iot,
+ ioh, TRM_S1040_SCSI_FIFO);
+ }
+ pSRB->SRBState = TRM_XFERPAD;
+ /*
+ * Set the transfer bus and direction
+ */
+ bval = ioDir == XFERDATAOUT ? SCMD_FIFO_OUT : SCMD_FIFO_IN;
+ }
+ /*
+ * it's important for atn stop
+ */
+ bus_space_write_2(iot,ioh,TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+ /*
+ * Tell the bus to do the transfer
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, bval);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_StatusPhase0
+ * Purpose : Update Target Status with data from SCSI FIFO
+ * Inputs : u_int8_t * - Set to PH_BUS_FREE
+ * ------------------------------------------------------------
+ */
+void
+trm_StatusPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+
+ pSRB->TargetStatus = bus_space_read_1(iot, ioh, TRM_S1040_SCSI_FIFO);
+
+ pSRB->SRBState = TRM_COMPLETED;
+ /*
+ * initial phase
+ */
+ *pscsi_status = PH_BUS_FREE;
+ /*
+ * it's important for atn stop
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+ /*
+ * Tell bus that the message was accepted
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_StatusPhase1
+ * Purpose : Clear FIFO of DMA and SCSI
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_StatusPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+
+ if ((bus_space_read_2(iot, ioh, TRM_S1040_DMA_COMMAND) & 0x0001) != 0) {
+ if ((bus_space_read_1(iot, ioh, TRM_S1040_SCSI_FIFOCNT) & 0x40)
+ == 0) {
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL,
+ DO_CLRFIFO);
+ }
+ if ((bus_space_read_2(iot, ioh,
+ TRM_S1040_DMA_FIFOCNT) & 0x8000) == 0) {
+ bus_space_write_1(iot, ioh,
+ TRM_S1040_DMA_CONTROL, CLRXFIFO);
+ }
+ } else {
+ if ((bus_space_read_2(iot, ioh,
+ TRM_S1040_DMA_FIFOCNT) & 0x8000) == 0) {
+ bus_space_write_1(iot, ioh,
+ TRM_S1040_DMA_CONTROL, CLRXFIFO);
+ }
+ if ((bus_space_read_1(iot, ioh,
+ TRM_S1040_SCSI_FIFOCNT) & 0x40) == 0) {
+ bus_space_write_2(iot, ioh,
+ TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
+ }
+ }
+ pSRB->SRBState = TRM_STATUS;
+ /*
+ * it's important for atn stop
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+ /*
+ * Tell the bus that the command is complete
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_MsgInPhase0
+ * Purpose :
+ * Inputs :
+ *
+ * extended message codes:
+ * code description
+ * ---- -----------
+ * 02h Reserved
+ * 00h MODIFY DATA POINTER
+ * 01h SYNCHRONOUS DATA TRANSFER REQUEST
+ * 03h WIDE DATA TRANSFER REQUEST
+ * 04h - 7Fh Reserved
+ * 80h - FFh Vendor specific
+ *
+ * ------------------------------------------------------------
+ */
+void
+trm_MsgInPhase0(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ struct trm_dcb *pDCB;
+ u_int8_t message_in_code, bIndex, message_in_tag_id;
+
+ pDCB = sc->pActiveDCB;
+
+ message_in_code = bus_space_read_1(iot, ioh, TRM_S1040_SCSI_FIFO);
+
+ if (pSRB->SRBState != TRM_EXTEND_MSGIN) {
+ switch (message_in_code) {
+ case MSG_DISCONNECT:
+ pSRB->SRBState = TRM_DISCONNECTED;
+ break;
+
+ case MSG_EXTENDED:
+ case MSG_SIMPLE_Q_TAG:
+ case MSG_HEAD_OF_Q_TAG:
+ case MSG_ORDERED_Q_TAG:
+ pSRB->SRBState = TRM_EXTEND_MSGIN;
+ /*
+ * extended message (01h)
+ */
+ bzero(&sc->MsgBuf[0], sizeof(sc->MsgBuf));
+ sc->MsgBuf[0] = message_in_code;
+ sc->MsgCnt = 1;
+ /*
+ * extended message length (n)
+ */
+ break;
+
+ case MSG_MESSAGE_REJECT:
+ /*
+ * Reject message
+ */
+ if ((pDCB->DCBFlag & TRM_DOING_WIDE_NEGO) != 0) {
+ /*
+ * do wide nego reject
+ */
+ pDCB = pSRB->pSRBDCB;
+
+ pDCB->DCBFlag &= ~TRM_DOING_WIDE_NEGO;
+ pDCB->DCBFlag |= TRM_WIDE_NEGO_DONE;
+
+ if ((pDCB->DCBFlag & TRM_SYNC_NEGO_ENABLE) != 0) {
+ /*
+ * Set ATN, in case ATN was clear
+ */
+ pSRB->SRBState = TRM_MSGOUT;
+ bus_space_write_2(iot, ioh,
+ TRM_S1040_SCSI_CONTROL, DO_SETATN);
+ } else {
+ /*
+ * Clear ATN
+ */
+ bus_space_write_2(iot, ioh,
+ TRM_S1040_SCSI_CONTROL, DO_CLRATN);
+ }
+
+ } else if ((pDCB->DCBFlag & TRM_DOING_SYNC_NEGO) != 0) {
+ /*
+ * do sync nego reject
+ */
+ pDCB = pSRB->pSRBDCB;
+
+ pDCB->DCBFlag &= ~TRM_DOING_SYNC_NEGO;
+
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
+ goto re_prog;
+ }
+ break;
+
+ case MSG_IGN_WIDE_RESIDUE:
+ bus_space_write_4(iot, ioh, TRM_S1040_SCSI_COUNTER, 1);
+ bus_space_read_1(iot, ioh, TRM_S1040_SCSI_FIFO);
+ break;
+
+ default:
+ break;
+ }
+
+ } else {
+
+ /*
+ * We are collecting an extended message. Save the latest byte and then
+ * check to see if the message is complete. If so, process it.
+ */
+ sc->MsgBuf[sc->MsgCnt++] = message_in_code;
+#ifdef TRM_DEBUG0
+ printf("%s: sc->MsgBuf = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ sc->sc_device.dv_xname,
+ sc->MsgBuf[0], sc->MsgBuf[1], sc->MsgBuf[2], sc->MsgBuf[3], sc->MsgBuf[4], sc->MsgBuf[5] );
+#endif
+ switch (sc->MsgBuf[0]) {
+ case MSG_SIMPLE_Q_TAG:
+ case MSG_HEAD_OF_Q_TAG:
+ case MSG_ORDERED_Q_TAG:
+ if (sc->MsgCnt == 2) {
+ pSRB->SRBState = TRM_FREE;
+ message_in_tag_id = sc->MsgBuf[1];
+ sc->MsgCnt = 0;
+ TAILQ_FOREACH(pSRB, &sc->goingSRB, link) {
+ if ((pSRB->pSRBDCB == pDCB) && (pSRB->TagNumber == message_in_tag_id))
+ break;
+ }
+ if ((pSRB != NULL) && (pSRB->SRBState == TRM_DISCONNECTED)) {
+ pDCB->pActiveSRB = pSRB;
+ pSRB->SRBState = TRM_DATA_XFER;
+ } else {
+ pSRB = &sc->SRB[0];
+ pSRB->SRBState = TRM_UNEXPECT_RESEL;
+ pDCB->pActiveSRB = pSRB;
+ trm_EnableMsgOut(sc, MSG_ABORT_TAG);
+ }
+ }
+ break;
+
+ case MSG_EXTENDED:
+ /* TODO XXXX: Correctly handling target initiated negotiations? */
+ if ((sc->MsgBuf[2] == MSG_EXT_WDTR) && (sc->MsgCnt == 4)) {
+ /*
+ * ======================================
+ * WIDE DATA TRANSFER REQUEST
+ * ======================================
+ * byte 0 : Extended message (01h)
+ * byte 1 : Extended message length (02h)
+ * byte 2 : WIDE DATA TRANSFER code (03h)
+ * byte 3 : Transfer width exponent
+ */
+
+ pSRB->SRBState = TRM_FREE;
+ pDCB->DCBFlag &= ~(TRM_WIDE_NEGO_ENABLE | TRM_DOING_WIDE_NEGO);
+
+ if (sc->MsgBuf[1] != MSG_EXT_WDTR_LEN)
+ goto reject_offer;
+
+ switch (sc->MsgBuf[3]) {
+ case MSG_EXT_WDTR_BUS_32_BIT:
+ if ((pDCB->DCBFlag & TRM_WIDE_NEGO_16BIT) == 0)
+ sc->MsgBuf[3] = MSG_EXT_WDTR_BUS_8_BIT;
+ else
+ sc->MsgBuf[3] = MSG_EXT_WDTR_BUS_16_BIT;
+ break;
+
+ case MSG_EXT_WDTR_BUS_16_BIT:
+ if ((pDCB->DCBFlag & TRM_WIDE_NEGO_16BIT) == 0) {
+ sc->MsgBuf[3] = MSG_EXT_WDTR_BUS_8_BIT;
+ break;
+ }
+ pDCB->SyncPeriod |= WIDE_SYNC;
+ /* FALL THROUGH == ACCEPT OFFER */
+
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ pSRB->SRBState = TRM_MSGOUT;
+ pDCB->DCBFlag |= (TRM_SYNC_NEGO_ENABLE | TRM_WIDE_NEGO_DONE);
+
+ if (pDCB->MaxNegoPeriod == 0) {
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+ goto re_prog;
+ }
+ break;
+
+ default:
+ pDCB->DCBFlag &= ~TRM_WIDE_NEGO_ENABLE;
+ pDCB->DCBFlag |= TRM_WIDE_NEGO_DONE;
+reject_offer:
+ sc->MsgCnt = 1;
+ sc->MsgBuf[0] = MSG_MESSAGE_REJECT;
+ break;
+ }
+
+ /* Echo accepted offer, or send revised offer */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_SETATN);
+
+ } else if ((sc->MsgBuf[2] == MSG_EXT_SDTR) && (sc->MsgCnt == 5)) {
+ /*
+ * =================================
+ * SYNCHRONOUS DATA TRANSFER REQUEST
+ * =================================
+ * byte 0 : Extended message (01h)
+ * byte 1 : Extended message length (03)
+ * byte 2 : SYNCHRONOUS DATA TRANSFER code (01h)
+ * byte 3 : Transfer period factor
+ * byte 4 : REQ/ACK offset
+ */
+
+ pSRB->SRBState = TRM_FREE;
+ pDCB->DCBFlag &= ~(TRM_SYNC_NEGO_ENABLE | TRM_DOING_SYNC_NEGO);
+
+ if (sc->MsgBuf[1] != MSG_EXT_SDTR_LEN)
+ goto reject_offer;
+
+ if ((sc->MsgBuf[3] == 0) || (sc->MsgBuf[4] == 0)) {
+ /*
+ * Asynchronous transfers
+ */
+ pDCB->SyncPeriod = 0;
+ pDCB->SyncOffset = 0;
+
+ } else {
+ /*
+ * Synchronous transfers
+ */
+ /*
+ * REQ/ACK offset
+ */
+ pDCB->SyncOffset = sc->MsgBuf[4];
+
+ for (bIndex = 0; bIndex < 7; bIndex++)
+ if (sc->MsgBuf[3] <= trm_clock_period[bIndex])
+ break;
+
+ pDCB->SyncPeriod |= (bIndex | ALT_SYNC);
+ }
+
+re_prog: /*
+ * program SCSI control register
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_SYNC, pDCB->SyncPeriod);
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_OFFSET, pDCB->SyncOffset);
+
+ trm_SetXferParams(sc, pDCB, (pDCB->DCBFlag & TRM_QUIRKS_VALID));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /*
+ * initial phase
+ */
+ *pscsi_status = PH_BUS_FREE;
+ /*
+ * it's important for atn stop
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+ /*
+ * Tell bus that the message was accepted
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_MsgInPhase1
+ * Purpose : Clear the FIFO
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_MsgInPhase1(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
+ bus_space_write_4(iot, ioh, TRM_S1040_SCSI_COUNTER, 1);
+
+ /*
+ * it's important for atn stop
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+ /*
+ * SCSI command
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_Nop
+ * Purpose : EMPTY
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_Nop(struct trm_softc *sc, struct trm_scsi_req_q *pSRB, u_int8_t *pscsi_status)
+{
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_SetXferParams
+ * Purpose : Set the Sync period, offset and mode for each device that has
+ * the same target as the given one (struct trm_dcb *)
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_SetXferParams(struct trm_softc *sc, struct trm_dcb *pDCB, int print_info)
+{
+ struct trm_dcb *pDCBTemp;
+ int lun, target;
+
+ /*
+ * set all lun device's period, offset
+ */
+#ifdef TRM_DEBUG0
+ printf("%s: trm_SetXferParams\n", sc->sc_device.dv_xname);
+#endif
+
+ target = pDCB->target;
+ for(lun = 0; lun < TRM_MAX_LUNS; lun++) {
+ pDCBTemp = sc->pDCB[target][lun];
+ if (pDCBTemp != NULL) {
+ pDCBTemp->DevMode = pDCB->DevMode;
+ pDCBTemp->MaxNegoPeriod = pDCB->MaxNegoPeriod;
+ pDCBTemp->SyncPeriod = pDCB->SyncPeriod;
+ pDCBTemp->SyncOffset = pDCB->SyncOffset;
+ pDCBTemp->DCBFlag = pDCB->DCBFlag;
+ }
+ }
+
+ if (print_info)
+ trm_print_info(sc, pDCB);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_Disconnect
+ * Purpose :
+ * Inputs :
+ *
+ * ---SCSI bus phase
+ * PH_DATA_OUT 0x00 Data out phase
+ * PH_DATA_IN 0x01 Data in phase
+ * PH_COMMAND 0x02 Command phase
+ * PH_STATUS 0x03 Status phase
+ * PH_BUS_FREE 0x04 Invalid phase used as bus free
+ * PH_BUS_FREE 0x05 Invalid phase used as bus free
+ * PH_MSG_OUT 0x06 Message out phase
+ * PH_MSG_IN 0x07 Message in phase
+ * ------------------------------------------------------------
+ */
+void
+trm_Disconnect(struct trm_softc *sc)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ struct trm_scsi_req_q *pSRB, *pNextSRB;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ struct trm_dcb *pDCB;
+ int j;
+
+#ifdef TRM_DEBUG0
+ printf("%s: trm_Disconnect\n", sc->sc_device.dv_xname);
+#endif
+
+ pDCB = sc->pActiveDCB;
+ if (pDCB == NULL) {
+ /* TODO: Why use a loop? Why not use DELAY(400)? */
+ for(j = 400; j > 0; --j)
+ DELAY(1); /* 1 msec */
+ bus_space_write_2(iot, ioh,
+ TRM_S1040_SCSI_CONTROL, (DO_CLRFIFO | DO_HWRESELECT));
+ return;
+ }
+
+ pSRB = pDCB->pActiveSRB;
+ sc->pActiveDCB = NULL;
+ pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */
+ bus_space_write_2(iot, ioh,
+ TRM_S1040_SCSI_CONTROL, (DO_CLRFIFO | DO_HWRESELECT));
+ DELAY(100);
+
+ switch (pSRB->SRBState) {
+ case TRM_UNEXPECT_RESEL:
+ pSRB->SRBState = TRM_FREE;
+ break;
+
+ case TRM_ABORT_SENT:
+ pSRB = TAILQ_FIRST(&sc->goingSRB);
+ while (pSRB != NULL) {
+ /*
+ * Need to save pNextSRB because trm_FinishSRB() puts
+ * pSRB in freeSRB queue, and thus its links no longer
+ * point to members of the goingSRB queue. This is why
+ * TAILQ_FOREACH() will not work for this traversal.
+ */
+ pNextSRB = TAILQ_NEXT(pSRB, link);
+ if (pSRB->pSRBDCB == pDCB) {
+ /* TODO XXXX: Is TIMED_OUT the best state to report? */
+ pSRB->SRBFlag |= TRM_SCSI_TIMED_OUT;
+ trm_FinishSRB(sc, pSRB);
+ }
+ pSRB = pNextSRB;
+ }
+ break;
+
+ case TRM_START:
+ case TRM_MSGOUT:
+ /*
+ * Selection time out
+ */
+ /* If not polling just keep trying until xs->stimeout expires */
+ if ((pSRB->xs->flags & SCSI_POLL) == 0) {
+ trm_RewaitSRB(sc, pSRB);
+ } else {
+ pSRB->TargetStatus = TRM_SCSI_SELECT_TIMEOUT;
+ goto disc1;
+ }
+ break;
+
+ case TRM_COMPLETED:
+disc1:
+ /*
+ * TRM_COMPLETED - remove id from mask of active tags
+ */
+ pDCB->pActiveSRB = NULL;
+ trm_FinishSRB(sc, pSRB);
+ break;
+
+ default:
+ break;
+ }
+
+ trm_StartWaitingSRB(sc);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_Reselect
+ * Purpose :
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_Reselect(struct trm_softc *sc)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ struct trm_scsi_req_q *pSRB;
+ struct trm_dcb *pDCB;
+ u_int16_t RselTarLunId;
+ u_int8_t target, lun;
+
+#ifdef TRM_DEBUG0
+ printf("%s: trm_Reselect\n", sc->sc_device.dv_xname);
+#endif
+
+ pDCB = sc->pActiveDCB;
+ if (pDCB != NULL) {
+ /*
+ * Arbitration lost but Reselection win
+ */
+ pSRB = pDCB->pActiveSRB;
+ trm_RewaitSRB(sc, pSRB);
+ }
+
+ /*
+ * Read Reselected Target Id and LUN
+ */
+ RselTarLunId = bus_space_read_2(iot, ioh, TRM_S1040_SCSI_TARGETID) & 0x1FFF;
+ /* TODO XXXX: Make endian independant! */
+ target = RselTarLunId & 0xff;
+ lun = (RselTarLunId >> 8) & 0xff;
+
+#ifdef TRM_DEBUG0
+ printf("%s: reselect - target = %d, lun = %d\n",
+ sc->sc_device.dv_xname, target, lun);
+#endif
+
+ if ((target < TRM_MAX_TARGETS) && (lun < TRM_MAX_LUNS))
+ pDCB = sc->pDCB[target][lun];
+ else
+ pDCB = NULL;
+
+ if (pDCB == NULL)
+ printf("%s: reselect - target = %d, lun = %d not found\n",
+ sc->sc_device.dv_xname, target, lun);
+
+ sc->pActiveDCB = pDCB;
+
+ /* TODO XXXX: This will crash if pDCB is ever NULL */
+ if ((pDCB->DCBFlag & TRM_USE_TAG_QUEUING) != 0) {
+ pSRB = &sc->SRB[0];
+ pDCB->pActiveSRB = pSRB;
+ } else {
+ pSRB = pDCB->pActiveSRB;
+ if (pSRB == NULL || (pSRB->SRBState != TRM_DISCONNECTED)) {
+ /*
+ * abort command
+ */
+ pSRB = &sc->SRB[0];
+ pSRB->SRBState = TRM_UNEXPECT_RESEL;
+ pDCB->pActiveSRB = pSRB;
+ trm_EnableMsgOut(sc, MSG_ABORT);
+ } else
+ pSRB->SRBState = TRM_DATA_XFER;
+ }
+ pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */
+
+ /*
+ * Program HA ID, target ID, period and offset
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_TARGETID, target);
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_HOSTID, sc->sc_AdaptSCSIID);
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_SYNC, pDCB->SyncPeriod);
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_OFFSET, pDCB->SyncOffset);
+
+ /*
+ * it's important for atn stop
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+ DELAY(30);
+
+ /*
+ * SCSI command
+ * to rls the /ACK signal
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_FinishSRB
+ * Purpose : Complete execution of a SCSI command
+ * Signal completion to the generic SCSI driver
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_FinishSRB(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
+{
+ struct scsi_inquiry_data *ptr;
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs = pSRB->xs;
+ struct trm_dcb *pDCB = pSRB->pSRBDCB;
+ int target, lun;
+
+#ifdef TRM_DEBUG0
+ printf("%s: trm_FinishSRB. sc = %p, pSRB = %p\n",
+ sc->sc_device.dv_xname, sc, pSRB);
+#endif
+ pDCB->DCBFlag &= ~TRM_QUEUE_FULL;
+
+ if (xs == NULL) {
+ trm_ReleaseSRB(sc, pSRB);
+ return;
+ }
+
+ timeout_del(&xs->stimeout);
+
+ xs->status = pSRB->TargetStatus;
+
+ switch (xs->status) {
+ case SCSI_INTERM_COND_MET:
+ case SCSI_COND_MET:
+ case SCSI_INTERM:
+ case SCSI_OK:
+ switch (pSRB->AdaptStatus) {
+ case TRM_STATUS_GOOD:
+ if ((pSRB->SRBFlag & TRM_PARITY_ERROR) != 0) {
+#ifdef TRM_DEBUG0
+ printf("%s: trm_FinishSRB. TRM_PARITY_ERROR\n",
+ sc->sc_device.dv_xname);
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+
+ } else if ((pSRB->SRBFlag & TRM_SCSI_TIMED_OUT) != 0) {
+ xs->error = XS_TIMEOUT;
+
+ } else if ((pSRB->SRBFlag & TRM_AUTO_REQSENSE) != 0) {
+ s1 = &pSRB->scsisense;
+ s2 = &xs->sense;
+
+ *s2 = *s1;
+
+ xs->status = SCSI_CHECK;
+ xs->error = XS_SENSE;
+
+ } else
+ xs->error = XS_NOERROR;
+ break;
+
+ case TRM_OVER_UNDER_RUN:
+#ifdef TRM_DEBUG0
+ printf("%s: trm_FinishSRB. TRM_OVER_UNDER_RUN\n",
+ sc->sc_device.dv_xname);
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ default:
+#ifdef TRM_DEBUG0
+ printf("%s: trm_FinishSRB. AdaptStatus Error = 0x%02x\n",
+ sc->sc_device.dv_xname, pSRB->AdaptStatus);
+#endif
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+ break;
+
+ case SCSI_TERMINATED:
+ case SCSI_ACA_ACTIVE:
+ case SCSI_CHECK:
+ if ((pSRB->SRBFlag & TRM_AUTO_REQSENSE) != 0)
+ xs->error = XS_DRIVER_STUFFUP;
+ else {
+ trm_RequestSense(sc, pSRB);
+ return;
+ }
+ break;
+
+ case SCSI_QUEUE_FULL:
+ /* this says no more until someone completes */
+ pDCB->DCBFlag |= TRM_QUEUE_FULL;
+ trm_RewaitSRB(sc, pSRB);
+ return;
+
+ case SCSI_RESV_CONFLICT:
+ case SCSI_BUSY:
+ xs->error = XS_BUSY;
+ break;
+
+ case TRM_SCSI_UNEXP_BUS_FREE:
+ xs->status = SCSI_OK;
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
+ case TRM_SCSI_BUS_RST_DETECTED:
+ xs->status = SCSI_OK;
+ xs->error = XS_RESET;
+ break;
+
+ case TRM_SCSI_SELECT_TIMEOUT:
+ xs->status = SCSI_OK;
+ xs->error = XS_SELTIMEOUT;
+ break;
+
+ default:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
+
+ target = xs->sc_link->target;
+ lun = xs->sc_link->lun;
+
+ if ((xs->flags & SCSI_POLL) != 0) {
+
+ if (xs->cmd->opcode == INQUIRY) {
+
+ ptr = (struct scsi_inquiry_data *) xs->data;
+
+ if ((xs->error != XS_NOERROR) ||
+ ((ptr->device & SID_QUAL_BAD_LU) == SID_QUAL_BAD_LU)) {
+#ifdef TRM_DEBUG0
+ printf("%s: trm_FinishSRB NO Device:target= %d,lun= %d\n",
+ sc->sc_device.dv_xname, target, lun);
+#endif
+ free(pDCB, M_DEVBUF);
+ sc->pDCB[target][lun] = NULL;
+ pDCB = NULL;
+
+ } else
+ pDCB->sc_link = xs->sc_link;
+ }
+ }
+
+ trm_ReleaseSRB(sc, pSRB);
+
+ xs->flags |= ITSDONE;
+
+ /*
+ * Notify cmd done
+ */
+#ifdef TRM_DEBUG0
+ if ((xs->error != 0) || (xs->status != 0) || ((xs->flags & SCSI_POLL) != 0))
+ printf("%s: trm_FinishSRB. %d/%d xs->cmd->opcode = 0x%02x, xs->error = %d, xs->status = %d\n",
+ sc->sc_device.dv_xname, target, lun, xs->cmd->opcode, xs->error, xs->status);
+#endif
+
+ scsi_done(xs);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_ReleaseSRB
+ * Purpose :
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_ReleaseSRB(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
+{
+ struct scsi_xfer *xs = pSRB->xs;
+ int intflag;
+
+ intflag = splbio();
+
+ if (pSRB->TagNumber != TRM_NO_TAG) {
+ pSRB->pSRBDCB->TagMask &= ~(1 << pSRB->TagNumber);
+ pSRB->TagNumber = TRM_NO_TAG;
+ }
+
+ if (xs != NULL) {
+ timeout_del(&xs->stimeout);
+
+ if (xs->datalen != 0) {
+ bus_dmamap_sync(sc->sc_dmatag, pSRB->dmamapxfer,
+ 0, pSRB->dmamapxfer->dm_mapsize,
+ (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmatag, pSRB->dmamapxfer);
+ }
+ }
+
+ /* SRB may have started & finished, or be waiting and timed out */
+ if ((pSRB->SRBFlag & TRM_ON_WAITING_SRB) != 0) {
+ pSRB->SRBFlag &= ~TRM_ON_WAITING_SRB;
+ TAILQ_REMOVE(&sc->waitingSRB, pSRB, link);
+ }
+ if ((pSRB->SRBFlag & TRM_ON_GOING_SRB) != 0) {
+ pSRB->SRBFlag &= ~TRM_ON_GOING_SRB;
+ TAILQ_REMOVE(&sc->goingSRB, pSRB, link);
+ }
+
+ bzero(&pSRB->SegmentX[0], sizeof(pSRB->SegmentX));
+ bzero(&pSRB->CmdBlock[0], sizeof(pSRB->CmdBlock));
+ bzero(&pSRB->scsisense, sizeof(pSRB->scsisense));
+
+ pSRB->SRBTotalXferLength = 0;
+ pSRB->SRBSGCount = 0;
+ pSRB->SRBSGIndex = 0;
+ pSRB->SRBFlag = 0;
+
+ pSRB->SRBState = TRM_FREE;
+ pSRB->AdaptStatus = TRM_STATUS_GOOD;
+ pSRB->TargetStatus = SCSI_OK;
+ pSRB->ScsiPhase = PH_BUS_FREE; /* SCSI bus free Phase */
+
+ pSRB->xs = NULL;
+ pSRB->pSRBDCB = NULL;
+
+ if (pSRB != &sc->SRB[0])
+ TAILQ_INSERT_TAIL(&sc->freeSRB, pSRB, link);
+
+ splx(intflag);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_GoingSRB_Done
+ * Purpose :
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_GoingSRB_Done(struct trm_softc *sc)
+{
+ struct trm_scsi_req_q *pSRB;
+
+ /* ASSUME we are inside a splbio()/splx() pair */
+
+ while ((pSRB = TAILQ_FIRST(&sc->goingSRB)) != NULL) {
+ /* TODO XXXX: Is TIMED_OUT the best status? */
+ pSRB->SRBFlag |= TRM_SCSI_TIMED_OUT;
+ trm_FinishSRB(sc, pSRB);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_ResetSCSIBus
+ * Purpose : Reset the SCSI bus
+ * Inputs : struct trm_softc * -
+ * ------------------------------------------------------------
+ */
+void
+trm_ResetSCSIBus(struct trm_softc *sc)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ int intflag;
+
+ intflag = splbio();
+
+ sc->sc_Flag |= RESET_DEV;
+
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
+ while ((bus_space_read_2(iot, ioh,
+ TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET) == 0);
+
+ splx(intflag);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_ScsiRstDetect
+ * Purpose :
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_ScsiRstDetect(struct trm_softc *sc)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ int wlval;
+
+#ifdef TRM_DEBUG0
+ printf("%s: trm_ScsiRstDetect\n", sc->sc_device.dv_xname);
+#endif
+
+ wlval = 1000;
+ /*
+ * delay 1 sec
+ */
+ while (--wlval != 0)
+ DELAY(1000);
+
+ bus_space_write_1(iot, ioh, TRM_S1040_DMA_CONTROL, STOPDMAXFER);
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
+
+ if ((sc->sc_Flag & RESET_DEV) != 0)
+ sc->sc_Flag |= RESET_DONE;
+ else {
+ sc->sc_Flag |= RESET_DETECT;
+ trm_ResetAllDevParam(sc);
+ trm_RecoverSRB(sc);
+ sc->pActiveDCB = NULL;
+ sc->sc_Flag = 0;
+ trm_StartWaitingSRB(sc);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_RequestSense
+ * Purpose :
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_RequestSense(struct trm_softc *sc, struct trm_scsi_req_q *pSRB)
+{
+ pSRB->SRBFlag |= TRM_AUTO_REQSENSE;
+
+ /*
+ * Status of initiator/target
+ */
+ pSRB->AdaptStatus = TRM_STATUS_GOOD;
+ pSRB->TargetStatus = SCSI_OK;
+ /*
+ * Status of initiator/target
+ */
+
+ pSRB->SegmentX[0].address = pSRB->scsisensePhyAddr;
+ pSRB->SegmentX[0].length = sizeof(struct scsi_sense_data);
+ pSRB->SRBTotalXferLength = sizeof(struct scsi_sense_data);
+ pSRB->SRBSGCount = 1;
+ pSRB->SRBSGIndex = 0;
+
+ bzero(&pSRB->CmdBlock[0], sizeof(pSRB->CmdBlock));
+
+ pSRB->CmdBlock[0] = REQUEST_SENSE;
+ pSRB->CmdBlock[1] = (pSRB->xs->sc_link->lun) << 5;
+ pSRB->CmdBlock[4] = sizeof(struct scsi_sense_data);
+
+ pSRB->ScsiCmdLen = 6;
+
+ if ((pSRB->xs != NULL) && ((pSRB->xs->flags & SCSI_POLL) == 0))
+ timeout_add(&pSRB->xs->stimeout, (pSRB->xs->timeout/1000) * hz);
+
+ if (trm_StartSRB(sc, pSRB) != 0)
+ trm_RewaitSRB(sc, pSRB);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_EnableMsgOut
+ * Purpose : set up MsgBuf to send out a single byte message
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_EnableMsgOut(struct trm_softc *sc, u_int8_t msg)
+{
+ sc->MsgBuf[0] = msg;
+ sc->MsgCnt = 1;
+
+ bus_space_write_2(sc->sc_iotag, sc->sc_iohandle, TRM_S1040_SCSI_CONTROL, DO_SETATN);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_linkSRB
+ * Purpose :
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_linkSRB(struct trm_softc *sc)
+{
+ struct trm_scsi_req_q *pSRB;
+ int i, intflag;
+
+ intflag = splbio();
+
+ for (i = 0; i < TRM_MAX_SRB_CNT; i++) {
+ pSRB = &sc->SRB[i];
+
+ pSRB->PhysSRB = sc->sc_dmamap_control->dm_segs[0].ds_addr
+ + i * sizeof(struct trm_scsi_req_q);
+
+ pSRB->SRBSGPhyAddr = sc->sc_dmamap_control->dm_segs[0].ds_addr
+ + i * sizeof(struct trm_scsi_req_q)
+ + offsetof(struct trm_scsi_req_q, SegmentX);
+
+ pSRB->scsisensePhyAddr = sc->sc_dmamap_control->dm_segs[0].ds_addr
+ + i * sizeof(struct trm_scsi_req_q)
+ + offsetof(struct trm_scsi_req_q, scsisense);
+
+ /*
+ * map all SRB space
+ */
+ if (bus_dmamap_create(sc->sc_dmatag, TRM_MAX_PHYSG_BYTE,
+ TRM_MAX_SG_LISTENTRY, TRM_MAX_PHYSG_BYTE, 0,
+ BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+ &pSRB->dmamapxfer) != 0) {
+ printf("%s: unable to create DMA transfer map\n",
+ sc->sc_device.dv_xname);
+ splx(intflag);
+ return;
+ }
+
+ if (i > 0)
+ /* We use sc->SRB[0] directly, so *don't* link it */
+ TAILQ_INSERT_TAIL(&sc->freeSRB, pSRB, link);
+#ifdef TRM_DEBUG0
+ printf("pSRB = %p ", pSRB);
+#endif
+ }
+#ifdef TRM_DEBUG0
+ printf("\n ");
+#endif
+ splx(intflag);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_minphys
+ * Purpose : limited by the number of segments in the dma segment list
+ * Inputs : *buf
+ * ------------------------------------------------------------
+ */
+void
+trm_minphys(struct buf *bp)
+{
+ if (bp->b_bcount > (TRM_MAX_SG_LISTENTRY-1) * (long) NBPG) {
+ bp->b_bcount = (TRM_MAX_SG_LISTENTRY-1) * (long) NBPG;
+ }
+ minphys(bp);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_initACB
+ * Purpose : initialize the internal structures for a given SCSI host
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_initACB(struct trm_softc *sc, int unit)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ struct trm_adapter_nvram *pEEpromBuf;
+ struct trm_dcb *pDCB;
+ int target, lun;
+
+ pEEpromBuf = &trm_eepromBuf[unit];
+ sc->sc_config = HCC_AUTOTERM | HCC_PARITY;
+
+ if ((bus_space_read_1(iot, ioh, TRM_S1040_GEN_STATUS) & WIDESCSI) != 0)
+ sc->sc_config |= HCC_WIDE_CARD;
+
+ if ((pEEpromBuf->NvramChannelCfg & NAC_POWERON_SCSI_RESET) != 0)
+ sc->sc_config |= HCC_SCSI_RESET;
+
+ TAILQ_INIT(&sc->freeSRB);
+ TAILQ_INIT(&sc->waitingSRB);
+ TAILQ_INIT(&sc->goingSRB);
+
+ sc->pActiveDCB = NULL;
+ sc->sc_AdapterUnit = unit;
+ sc->sc_AdaptSCSIID = pEEpromBuf->NvramScsiId;
+ sc->sc_TagMaxNum = 2 << pEEpromBuf->NvramMaxTag;
+ sc->sc_Flag = 0;
+
+ /*
+ * put all SRB's (except [0]) onto the freeSRB list
+ */
+ trm_linkSRB(sc);
+
+ /*
+ * allocate DCB array
+ */
+ for (target = 0; target < TRM_MAX_TARGETS; target++) {
+ if (target == sc->sc_AdaptSCSIID)
+ continue;
+
+ for (lun = 0; lun < TRM_MAX_LUNS; lun++) {
+ pDCB = (struct trm_dcb *)malloc(sizeof(struct trm_dcb), M_DEVBUF, M_NOWAIT);
+ sc->pDCB[target][lun] = pDCB;
+
+ if (pDCB == NULL)
+ continue;
+
+ bzero(pDCB, sizeof(struct trm_dcb));
+
+ pDCB->target = target;
+ pDCB->lun = lun;
+ pDCB->pActiveSRB = NULL;
+ }
+ }
+
+ sc->sc_adapter.scsi_cmd = trm_scsi_cmd;
+ sc->sc_adapter.scsi_minphys = trm_minphys;
+
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = sc->sc_AdaptSCSIID;
+ sc->sc_link.openings = 30; /* So TagMask (32 bit integer) always has space */
+ sc->sc_link.device = &trm_device;
+ sc->sc_link.adapter = &sc->sc_adapter;
+ sc->sc_link.adapter_buswidth = ((sc->sc_config & HCC_WIDE_CARD) == 0) ? 8:16;
+
+ trm_reset(sc);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_write_all
+ * Description : write pEEpromBuf 128 bytes to seeprom
+ * Input : iot, ioh - chip's base address
+ * Output : none
+ * ------------------------------------------------------------
+ */
+void
+trm_write_all(struct trm_adapter_nvram *pEEpromBuf, bus_space_tag_t iot,
+ bus_space_handle_t ioh)
+{
+ u_int8_t *bpEeprom = (u_int8_t *)pEEpromBuf;
+ u_int8_t bAddr;
+
+ /*
+ * Enable SEEPROM
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
+ (bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) | EN_EEPROM));
+ /*
+ * Write enable
+ */
+ trm_write_cmd(iot, ioh, 0x04, 0xFF);
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
+ trm_wait_30us(iot, ioh);
+ for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++)
+ trm_set_data(iot, ioh, bAddr, *bpEeprom);
+ /*
+ * Write disable
+ */
+ trm_write_cmd(iot, ioh, 0x04, 0x00);
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
+ trm_wait_30us(iot, ioh);
+ /*
+ * Disable SEEPROM
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
+ (bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) & ~EN_EEPROM));
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_set_data
+ * Description : write one byte to seeprom
+ * Input : iot, ioh - chip's base address
+ * bAddr - address of SEEPROM
+ * bData - data of SEEPROM
+ * Output : none
+ * ------------------------------------------------------------
+ */
+void
+trm_set_data(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t bAddr,
+ u_int8_t bData)
+{
+ u_int8_t bSendData;
+ int i;
+
+ /*
+ * Send write command & address
+ */
+ trm_write_cmd(iot, ioh, 0x05, bAddr);
+ /*
+ * Write data
+ */
+ for (i = 0; i < 8; i++, bData <<= 1) {
+ bSendData = NVR_SELECT;
+ if ((bData & 0x80) != 0) { /* Start from bit 7 */
+ bSendData |= NVR_BITOUT;
+ }
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, bSendData);
+ trm_wait_30us(iot, ioh);
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
+ (bSendData | NVR_CLOCK));
+ trm_wait_30us(iot, ioh);
+ }
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
+ trm_wait_30us(iot, ioh);
+ /*
+ * Disable chip select
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
+ trm_wait_30us(iot, ioh);
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
+ trm_wait_30us(iot, ioh);
+ /*
+ * Wait for write ready
+ */
+ for (;;) {
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
+ (NVR_SELECT | NVR_CLOCK));
+ trm_wait_30us(iot, ioh);
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
+ trm_wait_30us(iot, ioh);
+ if (bus_space_read_1(iot, ioh, TRM_S1040_GEN_NVRAM) & NVR_BITIN)
+ break;
+ }
+ /*
+ * Disable chip select
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_read_all
+ * Description : read seeprom 128 bytes to pEEpromBuf
+ * Input : pEEpromBuf, iot, ioh - chip's base address
+ * Output : none
+ * ------------------------------------------------------------
+ */
+void
+trm_read_all(struct trm_adapter_nvram *pEEpromBuf, bus_space_tag_t iot,
+ bus_space_handle_t ioh)
+{
+ u_int8_t *bpEeprom = (u_int8_t *)pEEpromBuf;
+ u_int8_t bAddr;
+
+ /*
+ * Enable SEEPROM
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
+ (bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) | EN_EEPROM));
+
+ for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++)
+ *bpEeprom = trm_get_data(iot, ioh, bAddr);
+
+ /*
+ * Disable SEEPROM
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_CONTROL,
+ (bus_space_read_1(iot, ioh, TRM_S1040_GEN_CONTROL) & ~EN_EEPROM));
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_get_data
+ * Description : read one byte from seeprom
+ * Input : iot, ioh - chip's base address
+ * bAddr - address of SEEPROM
+ * Output : bData - data of SEEPROM
+ * ------------------------------------------------------------
+ */
+u_int8_t
+trm_get_data( bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t bAddr)
+{
+ u_int8_t bReadData, bData;
+ int i;
+
+ bData = 0;
+
+ /*
+ * Send read command & address
+ */
+ trm_write_cmd(iot, ioh, 0x06, bAddr);
+
+ for (i = 0; i < 8; i++) {
+ /*
+ * Read data
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
+ (NVR_SELECT | NVR_CLOCK));
+ trm_wait_30us(iot, ioh);
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
+ /*
+ * Get data bit while falling edge
+ */
+ bReadData = bus_space_read_1(iot, ioh, TRM_S1040_GEN_NVRAM);
+ bData <<= 1;
+ if ((bReadData & NVR_BITIN) != 0)
+ bData |= 1;
+ trm_wait_30us(iot, ioh);
+ }
+ /*
+ * Disable chip select
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, 0);
+
+ return bData;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_wait_30us
+ * Description : wait 30 us
+ * Input : iot, ioh - chip's base address
+ * Output : none
+ * ------------------------------------------------------------
+ */
+void
+trm_wait_30us(bus_space_tag_t iot, bus_space_handle_t ioh)
+{
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_TIMER, 5);
+
+ while ((bus_space_read_1(iot, ioh, TRM_S1040_GEN_STATUS) & GTIMEOUT)
+ == 0);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_write_cmd
+ * Description : write SB and Op Code into seeprom
+ * Input : iot, ioh - chip's base address
+ * bCmd - SB + Op Code
+ * bAddr - address of SEEPROM
+ * Output : none
+ * ------------------------------------------------------------
+ */
+void
+trm_write_cmd( bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t bCmd,
+ u_int8_t bAddr)
+{
+ u_int8_t bSendData;
+ int i;
+
+ for (i = 0; i < 3; i++, bCmd <<= 1) {
+ /*
+ * Program SB + OP code
+ */
+ bSendData = NVR_SELECT;
+ if (bCmd & 0x04) /* Start from bit 2 */
+ bSendData |= NVR_BITOUT;
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, bSendData);
+ trm_wait_30us(iot, ioh);
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
+ (bSendData | NVR_CLOCK));
+ trm_wait_30us(iot, ioh);
+ }
+
+ for (i = 0; i < 7; i++, bAddr <<= 1) {
+ /*
+ * Program address
+ */
+ bSendData = NVR_SELECT;
+ if (bAddr & 0x40) { /* Start from bit 6 */
+ bSendData |= NVR_BITOUT;
+ }
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, bSendData);
+ trm_wait_30us(iot, ioh);
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM,
+ (bSendData | NVR_CLOCK));
+ trm_wait_30us(iot, ioh);
+ }
+ bus_space_write_1(iot, ioh, TRM_S1040_GEN_NVRAM, NVR_SELECT);
+ trm_wait_30us(iot, ioh);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_check_eeprom
+ * Description : read eeprom 128 bytes to pEEpromBuf and check
+ * checksum. If it is worong, updated with default value
+ * Input : eeprom, iot, ioh - chip's base address
+ * Output : none
+ * ------------------------------------------------------------
+ */
+void
+trm_check_eeprom(struct trm_adapter_nvram *pEEpromBuf, bus_space_tag_t iot,
+ bus_space_handle_t ioh)
+{
+ u_int32_t *dpEeprom = (u_int32_t *)pEEpromBuf->NvramTarget;
+ u_int32_t dAddr;
+ u_int16_t *wpEeprom = (u_int16_t *)pEEpromBuf;
+ u_int16_t wAddr, wCheckSum;
+
+#ifdef TRM_DEBUG0
+ printf("\ntrm_check_eeprom\n");
+#endif
+ trm_read_all(pEEpromBuf, iot, ioh);
+ wCheckSum = 0;
+ for (wAddr = 0; wAddr < 64; wAddr++, wpEeprom++)
+ wCheckSum += *wpEeprom;
+
+ if (wCheckSum != 0x1234) {
+#ifdef TRM_DEBUG0
+ printf("TRM_S1040 EEPROM Check Sum ERROR (load default)\n");
+#endif
+ /*
+ * Checksum error, load default
+ */
+ pEEpromBuf->NvramSubVendorID[0] = (u_int8_t)PCI_VENDOR_TEKRAM2;
+ pEEpromBuf->NvramSubVendorID[1] = (u_int8_t)(PCI_VENDOR_TEKRAM2
+ >> 8);
+ pEEpromBuf->NvramSubSysID[0] = (u_int8_t)
+ PCI_PRODUCT_TEKRAM2_DC3X5U;
+ pEEpromBuf->NvramSubSysID[1] = (u_int8_t)
+ (PCI_PRODUCT_TEKRAM2_DC3X5U >> 8);
+ pEEpromBuf->NvramSubClass = 0;
+ pEEpromBuf->NvramVendorID[0] = (u_int8_t)PCI_VENDOR_TEKRAM2;
+ pEEpromBuf->NvramVendorID[1] = (u_int8_t)(PCI_VENDOR_TEKRAM2
+ >> 8);
+ pEEpromBuf->NvramDeviceID[0] = (u_int8_t)
+ PCI_PRODUCT_TEKRAM2_DC3X5U;
+ pEEpromBuf->NvramDeviceID[1] = (u_int8_t)
+ (PCI_PRODUCT_TEKRAM2_DC3X5U >> 8);
+ pEEpromBuf->NvramReserved = 0;
+
+ for (dAddr = 0; dAddr < 16; dAddr++, dpEeprom++)
+ /*
+ * NvmTarCfg3,NvmTarCfg2,NvmTarPeriod,NvmTarCfg0
+ */
+ *dpEeprom = 0x00000077;
+
+ /*
+ * NvramMaxTag,NvramDelayTime,NvramChannelCfg,NvramScsiId
+ */
+ *dpEeprom++ = 0x04000F07;
+
+ /*
+ * NvramReserved1,NvramBootLun,NvramBootTarget,NvramReserved0
+ */
+ *dpEeprom++ = 0x00000015;
+ for (dAddr = 0; dAddr < 12; dAddr++, dpEeprom++)
+ *dpEeprom = 0;
+
+ pEEpromBuf->NvramCheckSum = 0;
+ for (wAddr = 0, wCheckSum =0; wAddr < 63; wAddr++, wpEeprom++)
+ wCheckSum += *wpEeprom;
+
+ *wpEeprom = 0x1234 - wCheckSum;
+ trm_write_all(pEEpromBuf, iot, ioh);
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_initAdapter
+ * Purpose : initialize the SCSI chip ctrl registers
+ * Inputs : psh - pointer to this host adapter's structure
+ * ------------------------------------------------------------
+ */
+void
+trm_initAdapter(struct trm_softc *sc)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ u_int16_t wval;
+ u_int8_t bval;
+
+ /*
+ * program configuration 0
+ */
+ if ((sc->sc_config & HCC_PARITY) != 0) {
+ bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK;
+ } else {
+ bval = PHASELATCH | INITIATOR | BLOCKRST;
+ }
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_CONFIG0, bval);
+ /*
+ * program configuration 1
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_CONFIG1, 0x13);
+ /*
+ * 250ms selection timeout
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_TIMEOUT, TRM_SEL_TIMEOUT);
+ /*
+ * Mask all the interrupt
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_DMA_INTEN, 0);
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_INTEN, 0);
+ /*
+ * Reset SCSI module
+ */
+ bus_space_write_2(iot, ioh, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
+ /*
+ * program Host ID
+ */
+ bval = sc->sc_AdaptSCSIID;
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_HOSTID, bval);
+ /*
+ * set ansynchronous transfer
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_OFFSET, 0);
+ /*
+ * Turn LED control off
+ */
+ wval = bus_space_read_2(iot, ioh, TRM_S1040_GEN_CONTROL) & 0x7F;
+ bus_space_write_2(iot, ioh, TRM_S1040_GEN_CONTROL, wval);
+ /*
+ * DMA config
+ */
+ wval = bus_space_read_2(iot, ioh, TRM_S1040_DMA_CONFIG) | DMA_ENHANCE;
+ bus_space_write_2(iot, ioh, TRM_S1040_DMA_CONFIG, wval);
+ /*
+ * Clear pending interrupt status
+ */
+ bus_space_read_1(iot, ioh, TRM_S1040_SCSI_INTSTATUS);
+ /*
+ * Enable SCSI interrupts
+ */
+ bus_space_write_1(iot, ioh, TRM_S1040_SCSI_INTEN,
+ (EN_SELECT | EN_SELTIMEOUT | EN_DISCONNECT | EN_RESELECTED |
+ EN_SCSIRESET | EN_BUSSERVICE | EN_CMDDONE));
+ bus_space_write_1(iot, ioh, TRM_S1040_DMA_INTEN, EN_SCSIINTR);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_init
+ * Purpose : initialize the internal structures for a given SCSI host
+ * Inputs : host - pointer to this host adapter's structure
+ * Preconditions : when this function is called, the chip_type field of
+ * the ACB structure MUST have been set.
+ * ------------------------------------------------------------
+ */
+int
+trm_init(struct trm_softc *sc, int unit)
+{
+ const bus_space_handle_t ioh = sc->sc_iohandle;
+ const bus_space_tag_t iot = sc->sc_iotag;
+ bus_dma_segment_t seg;
+ int error, rseg, all_srbs_size;
+
+ /*
+ * EEPROM CHECKSUM
+ */
+ trm_check_eeprom(&trm_eepromBuf[unit], iot, ioh);
+
+ /*
+ * MEMORY ALLOCATE FOR ADAPTER CONTROL BLOCK
+ */
+ /*
+ * allocate the space for all SCSI control blocks (SRB) for DMA memory.
+ */
+ all_srbs_size = TRM_MAX_SRB_CNT * sizeof(struct trm_scsi_req_q);
+
+ error = bus_dmamem_alloc(sc->sc_dmatag, all_srbs_size, NBPG, 0, &seg,
+ 1, &rseg, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ printf("%s: unable to allocate SCSI REQUEST BLOCKS, error = %d\n",
+ sc->sc_device.dv_xname, error);
+ /*errx(error, "%s: unable to allocate SCSI request blocks",
+ sc->sc_device.dv_xname);*/
+ return -1;
+ }
+
+ error = bus_dmamem_map(sc->sc_dmatag, &seg, rseg, all_srbs_size,
+ (caddr_t *)&sc->SRB, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
+ if (error != 0) {
+ printf("%s: unable to map SCSI REQUEST BLOCKS, error = %d\n",
+ sc->sc_device.dv_xname, error);
+ /*errx(error, "unable to map SCSI request blocks");*/
+ return -1;
+ }
+
+ error = bus_dmamap_create(sc->sc_dmatag, all_srbs_size, 1,
+ all_srbs_size, 0, BUS_DMA_NOWAIT,&sc->sc_dmamap_control);
+ if (error != 0) {
+ printf("%s: unable to create SRB DMA maps, error = %d\n",
+ sc->sc_device.dv_xname, error);
+ /*errx(error, "unable to create SRB DMA maps");*/
+ return -1;
+ }
+
+ error = bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap_control,
+ sc->SRB, all_srbs_size, NULL, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ printf("%s: unable to load SRB DMA maps, error = %d\n",
+ sc->sc_device.dv_xname, error);
+ /*errx(error, "unable to load SRB DMA maps");*/
+ return -1;
+ }
+#ifdef TRM_DEBUG0
+ printf("\n\n%s: all_srbs_size=%x\n",
+ sc->sc_device.dv_xname, all_srbs_size);
+#endif
+ bzero(sc->SRB, all_srbs_size);
+ trm_initACB(sc, unit);
+ trm_initAdapter(sc);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------
+ * Function : trm_print_info
+ * Purpose : Print the DCB negotiation information
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_print_info(struct trm_softc *sc, struct trm_dcb *pDCB)
+{
+ int syncXfer, index;
+
+ index = pDCB->SyncPeriod & ~(WIDE_SYNC | ALT_SYNC);
+
+ printf("%s: target %d using ", sc->sc_device.dv_xname, pDCB->target);
+ if ((pDCB->SyncPeriod & WIDE_SYNC) != 0)
+ printf("16 bit ");
+ else
+ printf("8 bit ");
+
+ if (pDCB->SyncOffset == 0)
+ printf("Asynchronous ");
+ else {
+ syncXfer = 100000 / (trm_clock_period[index] * 4);
+ printf("%d.%01d MHz, Offset %d ",
+ syncXfer / 100, syncXfer % 100, pDCB->SyncOffset);
+ }
+ printf("data transfers ");
+
+ if ((pDCB->DCBFlag & TRM_USE_TAG_QUEUING) != 0)
+ printf("with Tag Queuing");
+
+ printf("\n");
+}
diff --git a/sys/dev/ic/trm.h b/sys/dev/ic/trm.h
new file mode 100644
index 00000000000..2251baf89bf
--- /dev/null
+++ b/sys/dev/ic/trm.h
@@ -0,0 +1,529 @@
+/* $OpenBSD: trm.h,v 1.1 2002/02/18 01:55:30 krw Exp $
+ * ------------------------------------------------------------
+ * O.S : OpenBSD
+ * File Name : trm.h
+ * Device Driver for Tekram DC395U/UW/F,DC315/U
+ * PCI SCSI Bus Master Host Adapter
+ * (SCSI chip set used Tekram ASIC TRM-S1040)
+ *
+ * (C)Copyright 1995-1999 Tekram Technology Co., Ltd.
+ * (C)Copyright 2001-2002 Ashley R. Martens and Kenneth R Westerback
+ * ------------------------------------------------------------
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 _TRM_H
+#define _TRM_H
+
+/*
+ * ------------------------------------------------------------
+ * Segment Entry
+ * ------------------------------------------------------------
+ */
+struct SGentry
+{
+ u_int32_t address;
+ u_int32_t length;
+};
+
+/*
+ * -----------------------------------------------------------------------
+ * feature of chip set MAX value
+ * -----------------------------------------------------------------------
+ */
+
+#define TRM_MAX_ADAPTER_NUM 4
+#define TRM_MAX_TARGETS 16
+#define TRM_MAX_LUNS 8
+#define TRM_MAX_SG_LISTENTRY 32
+#define TRM_MAX_CMD_PER_LUN 32
+#define TRM_MAX_SRB_CNT TRM_MAX_CMD_PER_LUN*4
+#define TRM_MAX_PHYSG_BYTE ((TRM_MAX_SG_LISTENTRY - 1) << PGSHIFT)
+#define TRM_MAX_SYNC_OFFSET 15
+#define TRM_SEL_TIMEOUT 153 /* 250 ms selection timeout (@40MHz) */
+
+/*
+ *-----------------------------------------------------------------------
+ * SCSI Request Block
+ *-----------------------------------------------------------------------
+ */
+struct trm_scsi_req_q
+{
+ TAILQ_ENTRY(trm_scsi_req_q) link;
+ bus_dmamap_t dmamapxfer;
+ u_int32_t PhysSRB;
+ u_int32_t SRBTotalXferLength;
+ u_int32_t SRBSGPhyAddr; /* a segment starting address */
+
+ u_int16_t SRBState; /* State machine */
+#define TRM_FREE 0x0000
+#define TRM_WAIT 0x0001
+#define TRM_READY 0x0002
+#define TRM_MSGOUT 0x0004 /*arbitration+msg_out 1st byte */
+#define TRM_EXTEND_MSGIN 0x0010
+#define TRM_COMMAND 0x0020
+#define TRM_START 0x0040 /*arbitration+msg_out+command_out */
+#define TRM_DISCONNECTED 0x0080
+#define TRM_DATA_XFER 0x0100
+#define TRM_XFERPAD 0x0200
+#define TRM_STATUS 0x0400
+#define TRM_COMPLETED 0x0800
+#define TRM_ABORT_SENT 0x1000
+#define TRM_UNEXPECT_RESEL 0x8000
+
+ u_int8_t AdaptStatus;
+#define TRM_STATUS_GOOD 0x00
+#define TRM_SELECTION_TIMED_OUT 0x11
+#define TRM_OVER_UNDER_RUN 0x12
+#define TRM_UNEXP_BUS_FREE 0x13
+#define TRM_TARGET_PHASE_F 0x14
+#define TRM_INVALID_CCB_OP 0x16
+#define TRM_LINK_CCB_BAD 0x17
+#define TRM_BAD_TARGET_DIR 0x18
+#define TRM_DUPLICATE_CCB 0x19
+#define TRM_BAD_CCB_OR_SG 0x1A
+#define TRM_ABORT 0xFF
+
+ u_int8_t CmdBlock[12];
+
+ u_int8_t ScsiCmdLen;
+ u_int8_t ScsiPhase;
+
+ u_int8_t SRBFlag;
+#define TRM_AUTO_REQSENSE 0x01
+#define TRM_SCSI_TIMED_OUT 0x02
+#define TRM_PARITY_ERROR 0x04
+#define TRM_ON_GOING_SRB 0x08
+#define TRM_ON_WAITING_SRB 0x10
+
+ u_int8_t SRBSGCount;
+ u_int8_t SRBSGIndex;
+ u_int8_t TagNumber;
+#define TRM_NO_TAG 0x00
+
+ u_int8_t TargetStatus; /* SCSI status codes + Tekram: */
+#define TRM_SCSI_UNEXP_BUS_FREE 0xFD /* Unexpect Bus Free */
+#define TRM_SCSI_BUS_RST_DETECTED 0xFE /* Scsi Bus Reset detected */
+#define TRM_SCSI_SELECT_TIMEOUT 0xFF /* Selection Time out */
+
+ struct trm_dcb *pSRBDCB;
+
+ struct SGentry SegmentX[TRM_MAX_SG_LISTENTRY];
+
+ struct scsi_xfer *xs;
+
+ struct scsi_sense_data scsisense;
+ u_int32_t scsisensePhyAddr;
+};
+
+TAILQ_HEAD(SRB_HEAD, trm_scsi_req_q);
+
+/*
+ *-----------------------------------------------------------------------
+ * Device Control Block
+ *-----------------------------------------------------------------------
+ */
+struct trm_dcb
+{
+ u_int32_t TagMask;
+
+ u_int16_t DCBFlag;
+#define TRM_WIDE_NEGO_ENABLE 0x0001
+#define TRM_DOING_WIDE_NEGO 0x0002
+#define TRM_WIDE_NEGO_DONE 0x0004
+#define TRM_SYNC_NEGO_ENABLE 0x0008
+#define TRM_DOING_SYNC_NEGO 0x0010
+#define TRM_USE_TAG_QUEUING 0x0020
+#define TRM_QUEUE_FULL 0x0040
+#define TRM_WIDE_NEGO_16BIT 0x0080
+#define TRM_QUIRKS_VALID 0x0100
+#define TRM_BAD_DCB 0x0200
+
+ u_int8_t DevMode; /* trm_target_nvram.NvmTarCfg0 */
+
+ u_int8_t MaxNegoPeriod; /* Maximum allow sync period */
+ u_int8_t SyncPeriod; /* Current sync period */
+ u_int8_t SyncOffset; /* Current sync offset */
+
+ u_int8_t target; /* SCSI Target ID */
+ u_int8_t lun; /* SCSI Logical Unit Number */
+
+ u_int8_t IdentifyMsg;
+
+ struct scsi_link *sc_link;
+ struct trm_scsi_req_q *pActiveSRB;
+};
+
+/*
+ *-----------------------------------------------------------------------
+ * Adapter Control Block
+ *-----------------------------------------------------------------------
+ */
+struct trm_softc
+{
+ struct device sc_device;
+
+ bus_space_handle_t sc_iohandle;
+ bus_space_tag_t sc_iotag;
+ bus_dma_tag_t sc_dmatag;
+ bus_dmamap_t sc_dmamap_control; /* map the control structures */
+
+ u_int16_t sc_AdapterUnit; /* nth Adapter this driver */
+
+ u_int8_t sc_AdaptSCSIID; /* Adapter SCSI Target ID */
+ u_int8_t sc_TagMaxNum;
+
+ u_int8_t sc_config;
+#define HCC_WIDE_CARD 0x20
+#define HCC_SCSI_RESET 0x10
+#define HCC_PARITY 0x08
+#define HCC_AUTOTERM 0x04
+#define HCC_LOW8TERM 0x02
+#define HCC_UP8TERM 0x01
+
+ u_int8_t sc_Flag;
+#define RESET_DEV 0x01
+#define RESET_DETECT 0x02
+#define RESET_DONE 0x04
+
+ u_int8_t MsgCnt;
+ u_int8_t MsgBuf[6];
+
+ /*
+ *----------------------------------
+ * Link to the generic SCSI driver
+ *----------------------------------
+ */
+ struct scsi_adapter sc_adapter;
+ struct scsi_link sc_link;
+
+ struct SRB_HEAD freeSRB;
+ struct SRB_HEAD goingSRB;
+ struct SRB_HEAD waitingSRB;
+
+ struct trm_dcb *pActiveDCB;
+ struct trm_dcb *pDCB[TRM_MAX_TARGETS][TRM_MAX_LUNS];
+
+ struct trm_scsi_req_q *SRB;
+};
+
+/*
+ * The SEEPROM structure for TRM_S1040
+ */
+struct trm_target_nvram
+{
+ u_int8_t NvmTarCfg0; /* Target configuration byte 0 */
+#define TRM_WIDE 0x20 /* Wide negotiate */
+#define TRM_TAG_QUEUING 0x10 /* Enable SCSI tag queuing */
+#define TRM_SEND_START 0x08 /* Send start command SPINUP */
+#define TRM_DISCONNECT 0x04 /* Enable SCSI disconnect */
+#define TRM_SYNC 0x02 /* Sync negotiation */
+#define TRM_PARITY 0x01 /* (it should be defined at NAC ) */
+
+ u_int8_t NvmTarPeriod; /* Target period */
+ u_int8_t NvmTarCfg2; /* Target configuration byte 2 */
+ u_int8_t NvmTarCfg3; /* Target configuration byte 3 */
+};
+
+struct trm_adapter_nvram
+{
+ u_int8_t NvramSubVendorID[2]; /*0,1 Sub Vendor ID */
+ u_int8_t NvramSubSysID[2]; /*2,3 Sub System ID */
+ u_int8_t NvramSubClass; /*4 Sub Class */
+ u_int8_t NvramVendorID[2]; /*5,6 Vendor ID */
+ u_int8_t NvramDeviceID[2]; /*7,8 Device ID */
+ u_int8_t NvramReserved; /*9 Reserved */
+ struct trm_target_nvram NvramTarget[TRM_MAX_TARGETS]; /* 10 */
+ u_int8_t NvramScsiId; /*74 Host Adapter SCSI ID */
+ u_int8_t NvramChannelCfg; /*75 Channel configuration */
+#define NAC_SCANLUN 0x20 /* Include LUN as BIOS device */
+#define NAC_POWERON_SCSI_RESET 0x04 /* Power on reset enable */
+#define NAC_GREATER_1G 0x02 /* > 1G support enable */
+#define NAC_GT2DRIVES 0x01 /* Support more than 2 drives */
+ u_int8_t NvramDelayTime; /*76 Power on delay time */
+ u_int8_t NvramMaxTag; /*77 Maximum tags */
+ u_int8_t NvramReserved0; /*78 */
+ u_int8_t NvramBootTarget; /*79 */
+ u_int8_t NvramBootLun; /*80 */
+ u_int8_t NvramReserved1; /*81 */
+ u_int16_t Reserved[22]; /*82,..125 */
+ u_int16_t NvramCheckSum; /*126,127 */
+};
+
+/*
+ * The PCI configuration register offsets for the TRM_S1040, and
+ * the associated bit definitions.
+ */
+
+#define TRM_S1040_ID 0x00 /* Vendor and Device ID */
+#define TRM_S1040_COMMAND 0x04 /* PCI command register */
+#define TRM_S1040_IOBASE 0x10 /* I/O Space base address */
+#define TRM_S1040_ROMBASE 0x30 /* Expansion ROM Base Address */
+#define TRM_S1040_INTLINE 0x3C /* Interrupt line */
+
+#define TRM_S1040_SCSI_STATUS 0x80 /* SCSI Status (R) */
+#define COMMANDPHASEDONE 0x2000 /* SCSI command phase done */
+#define SCSIXFERDONE 0x0800 /* SCSI SCSI transfer done */
+#define SCSIXFERCNT_2_ZERO 0x0100 /* SCSI SCSI transfer count to zero */
+#define SCSIINTERRUPT 0x0080 /* SCSI interrupt pending */
+#define COMMANDABORT 0x0040 /* SCSI command abort */
+#define SEQUENCERACTIVE 0x0020 /* SCSI sequencer active */
+#define PHASEMISMATCH 0x0010 /* SCSI phase mismatch */
+#define PARITYERROR 0x0008 /* SCSI parity error */
+#define PHASEMASK 0x0007 /* Phase MSG/CD/IO */
+#define PH_DATA_OUT 0x00 /* Data out phase */
+#define PH_DATA_IN 0x01 /* Data in phase */
+#define PH_COMMAND 0x02 /* Command phase */
+#define PH_STATUS 0x03 /* Status phase */
+#define PH_BUS_FREE 0x05 /* Invalid phase used as bus free */
+#define PH_MSG_OUT 0x06 /* Message out phase */
+#define PH_MSG_IN 0x07 /* Message in phase */
+#define TRM_S1040_SCSI_CONTROL 0x80 /* SCSI Control (W) */
+#define DO_CLRATN 0x0400 /* Clear ATN */
+#define DO_SETATN 0x0200 /* Set ATN */
+#define DO_CMDABORT 0x0100 /* Abort SCSI command */
+#define DO_RSTMODULE 0x0010 /* Reset SCSI chip */
+#define DO_RSTSCSI 0x0008 /* Reset SCSI bus */
+#define DO_CLRFIFO 0x0004 /* Clear SCSI transfer FIFO */
+#define DO_DATALATCH 0x0002 /* Enable SCSI bus data latch */
+#define DO_HWRESELECT 0x0001 /* Enable hardware reselection */
+#define TRM_S1040_SCSI_FIFOCNT 0x82 /* SCSI FIFO Counter 5bits(R) */
+#define TRM_S1040_SCSI_SIGNAL 0x83 /* SCSI low level signal (R/W) */
+#define TRM_S1040_SCSI_INTSTATUS 0x84 /* SCSI Interrupt Status (R) */
+#define INT_SCAM 0x80 /* SCAM selection interrupt */
+#define INT_SELECT 0x40 /* Selection interrupt */
+#define INT_SELTIMEOUT 0x20 /* Selection timeout interrupt */
+#define INT_DISCONNECT 0x10 /* Bus disconnected interrupt */
+#define INT_RESELECTED 0x08 /* Reselected interrupt */
+#define INT_SCSIRESET 0x04 /* SCSI reset detected interrupt */
+#define INT_BUSSERVICE 0x02 /* Bus service interrupt */
+#define INT_CMDDONE 0x01 /* SCSI command done interrupt */
+#define TRM_S1040_SCSI_OFFSET 0x84 /* SCSI Offset Count (W) */
+/*
+ * Bit Name Definition
+ * 07-05 0 RSVD Reversed. Always 0.
+ * 04 0 OFFSET4 Reversed for LVDS. Always 0.
+ * 03-00 0 OFFSET[03:00] Offset number from 0 to 15
+ */
+#define TRM_S1040_SCSI_SYNC 0x85 /* SCSI Synchronous Control (R/W) */
+#define LVDS_SYNC 0x20 /* Enable LVDS synchronous */
+#define WIDE_SYNC 0x10 /* Enable WIDE synchronous */
+#define ALT_SYNC 0x08 /* Enable Fast-20 alternate synchronous */
+/*
+ * SYNCM 7 6 5 4 3 2 1 0
+ * Name RSVD RSVD LVDS WIDE ALTPERD PERIOD2 PERIOD1 PERIOD0
+ * Default 0 0 0 0 0 0 0 0
+ *
+ *
+ * Bit Name Definition
+ * --- ---- ----------
+ * 07-06 0 RSVD Reversed. Always read 0
+ * 05 0 LVDS Reversed. Always read 0
+ * 04 0 WIDE/WSCSI Enable wide (16-bits) SCSI transfer.
+ * 03 0 ALTPERD/ALTPD Alternate (Sync./Period) mode.
+ *
+ * @@ When this bit is set,
+ * the synchronous period bits 2:0
+ * in the Synchronous Mode register
+ * are used to transfer data
+ * at the Fast-20 rate.
+ * @@ When this bit is reset,
+ * the synchronous period bits 2:0
+ * in the Synchronous Mode Register
+ * are used to transfer data
+ * at the Fast-40 rate.
+ *
+ * 02-00 0 PERIOD[2:0]/SXPD[02:00] Synchronous SCSI Transfer Rate.
+ * These 3 bits specify
+ * the Synchronous SCSI Transfer Rate
+ * for Fast-20 and Fast-10.
+ * These bits are also reset
+ * by a SCSI Bus reset.
+ *
+ * For Fast-10 bit ALTPD = 0 and LVDS = 0
+ * and bit2,bit1,bit0 is defined as follows :
+ *
+ * 000 100ns, 10.0 Mbytes/s
+ * 001 150ns, 6.6 Mbytes/s
+ * 010 200ns, 5.0 Mbytes/s
+ * 011 250ns, 4.0 Mbytes/s
+ * 100 300ns, 3.3 Mbytes/s
+ * 101 350ns, 2.8 Mbytes/s
+ * 110 400ns, 2.5 Mbytes/s
+ * 111 450ns, 2.2 Mbytes/s
+ *
+ * For Fast-20 bit ALTPD = 1 and LVDS = 0
+ * and bit2,bit1,bit0 is defined as follows :
+ *
+ * 000 50ns, 20.0 Mbytes/s
+ * 001 75ns, 13.3 Mbytes/s
+ * 010 100ns, 10.0 Mbytes/s
+ * 011 125ns, 8.0 Mbytes/s
+ * 100 150ns, 6.6 Mbytes/s
+ * 101 175ns, 5.7 Mbytes/s
+ * 110 200ns, 5.0 Mbytes/s
+ * 111 250ns, 4.0 Mbytes/s
+ *
+ * For Fast-40 bit ALTPD = 0 and LVDS = 1
+ * and bit2,bit1,bit0 is defined as follows :
+ *
+ * 000 25ns, 40.0 Mbytes/s
+ * 001 50ns, 20.0 Mbytes/s
+ * 010 75ns, 13.3 Mbytes/s
+ * 011 100ns, 10.0 Mbytes/s
+ * 100 125ns, 8.0 Mbytes/s
+ * 101 150ns, 6.6 Mbytes/s
+ * 110 175ns, 5.7 Mbytes/s
+ * 111 200ns, 5.0 Mbytes/s
+ */
+#define TRM_S1040_SCSI_TARGETID 0x86 /* SCSI Target ID (R/W) */
+#define TRM_S1040_SCSI_IDMSG 0x87 /* SCSI Identify Message (R) */
+#define TRM_S1040_SCSI_HOSTID 0x87 /* SCSI Host ID (W) */
+#define TRM_S1040_SCSI_COUNTER 0x88 /* SCSI Transfer Counter 24bits(R/W) */
+#define TRM_S1040_SCSI_INTEN 0x8C /* SCSI Interrupt Enable (R/W) */
+#define EN_SCAM 0x80 /* Enable SCAM selection interrupt */
+#define EN_SELECT 0x40 /* Enable selection interrupt */
+#define EN_SELTIMEOUT 0x20 /* Enable selection timeout interrupt */
+#define EN_DISCONNECT 0x10 /* Enable bus disconnected interrupt */
+#define EN_RESELECTED 0x08 /* Enable reselected interrupt */
+#define EN_SCSIRESET 0x04 /* Enable SCSI reset detected interrupt*/
+#define EN_BUSSERVICE 0x02 /* Enable bus service interrupt */
+#define EN_CMDDONE 0x01 /* Enable SCSI command done interrupt */
+#define TRM_S1040_SCSI_CONFIG0 0x8D /* SCSI Configuration 0 (R/W) */
+#define PHASELATCH 0x40 /* Enable phase latch */
+#define INITIATOR 0x20 /* Enable initiator mode */
+#define PARITYCHECK 0x10 /* Enable parity check */
+#define BLOCKRST 0x01 /* Disable SCSI reset1 */
+#define TRM_S1040_SCSI_CONFIG1 0x8E /* SCSI Configuration 1 (R/W) */
+#define ACTIVE_NEGPLUS 0x10 /* Enhance active negation */
+#define FILTER_DISABLE 0x08 /* Disable SCSI data filter */
+#define ACTIVE_NEG 0x02 /* Enable active negation */
+#define TRM_S1040_SCSI_CONFIG2 0x8F /* SCSI Configuration 2 (R/W) */
+#define TRM_S1040_SCSI_COMMAND 0x90 /* SCSI Command (R/W) */
+#define SCMD_COMP 0x12 /* Command complete */
+#define SCMD_SEL_ATN 0x60 /* Selection with ATN */
+#define SCMD_SEL_ATN3 0x64 /* Selection with ATN3 */
+#define SCMD_SEL_ATNSTOP 0xB8 /* Selection with ATN and Stop */
+#define SCMD_FIFO_OUT 0xC0 /* SCSI FIFO transfer out */
+#define SCMD_DMA_OUT 0xC1 /* SCSI DMA transfer out */
+#define SCMD_FIFO_IN 0xC2 /* SCSI FIFO transfer in */
+#define SCMD_DMA_IN 0xC3 /* SCSI DMA transfer in */
+#define SCMD_MSGACCEPT 0xD8 /* Message accept */
+/*
+ * Code Command Description
+ *
+ * 02 Enable reselection with FIFO
+ * 40 Select without ATN with FIFO
+ * 60 Select with ATN with FIFO
+ * 64 Select with ATN3 with FIFO
+ * A0 Select with ATN and stop with FIFO
+ * C0 Transfer information out with FIFO
+ * C1 Transfer information out with DMA
+ * C2 Transfer information in with FIFO
+ * C3 Transfer information in with DMA
+ * 12 Initiator command complete with FIFO
+ * 50 Initiator transfer information out sequence without ATN with FIFO
+ * 70 Initiator transfer information out sequence with ATN with FIFO
+ * 74 Initiator transfer information out sequence with ATN3 with FIFO
+ * 52 Initiator transfer information in sequence without ATN with FIFO
+ * 72 Initiator transfer information in sequence with ATN with FIFO
+ * 76 Initiator transfer information in sequence with ATN3 with FIFO
+ * 90 Initiator transfer information out command complete with FIFO
+ * 92 Initiator transfer information in command complete with FIFO
+ * D2 Enable selection
+ * 08 Reselection
+ * 48 Disconnect command with FIFO
+ * 88 Terminate command with FIFO
+ * C8 Target command complete with FIFO
+ * 18 SCAM Arbitration/ Selection
+ * 5A Enable reselection
+ * 98 Select without ATN with FIFO
+ * B8 Select with ATN with FIFO
+ * D8 Message Accepted
+ * 58 NOP
+ */
+#define TRM_S1040_SCSI_TIMEOUT 0x91 /* SCSI Time Out Value (R/W) */
+#define TRM_S1040_SCSI_FIFO 0x98 /* SCSI FIFO (R/W) */
+#define TRM_S1040_SCSI_TCR0 0x9C /* SCSI Target Control 0 (R/W) */
+#define TCR0_WIDE_NEGO_DONE 0x8000 /* Wide nego done */
+#define TCR0_SYNC_NEGO_DONE 0x4000 /* Synchronous nego done */
+#define TCR0_ENABLE_LVDS 0x2000 /* Enable LVDS synchronous */
+#define TCR0_ENABLE_WIDE 0x1000 /* Enable WIDE synchronous */
+#define TCR0_ENABLE_ALT 0x0800 /* Enable alternate synchronous */
+#define TCR0_PERIOD_MASK 0x0700 /* Transfer rate */
+#define TCR0_DO_WIDE_NEGO 0x0080 /* Do wide NEGO */
+#define TCR0_DO_SYNC_NEGO 0x0040 /* Do sync NEGO */
+#define TCR0_DISCONNECT_EN 0x0020 /* Disconnection enable */
+#define TCR0_OFFSET_MASK 0x001F /* Offset number */
+#define TRM_S1040_SCSI_TCR1 0x9E /* SCSI Target Control 1 (R/W) */
+#define MAXTAG_MASK 0x7F00 /* Maximum tags (127) */
+#define NON_TAG_BUSY 0x0080 /* Non tag command active */
+#define ACTTAG_MASK 0x007F /* Active tags */
+
+#define TRM_S1040_DMA_COMMAND 0xA0 /* DMA Command (R/W) */
+#define XFERDATAIN 0x0103 /* Transfer data in */
+#define XFERDATAOUT 0x0102 /* Transfer data out */
+#define TRM_S1040_DMA_FIFOCNT 0xA1 /* DMA FIFO Counter (R) */
+#define TRM_S1040_DMA_CONTROL 0xA1 /* DMA Control (W) */
+#define STOPDMAXFER 0x08 /* Stop DMA transfer */
+#define ABORTXFER 0x04 /* Abort DMA transfer */
+#define CLRXFIFO 0x02 /* Clear DMA transfer FIFO */
+#define STARTDMAXFER 0x01 /* Start DMA transfer */
+#define TRM_S1040_DMA_STATUS 0xA3 /* DMA Interrupt Status (R/W) */
+#define XFERPENDING 0x80 /* Transfer pending */
+#define DMAXFERCOMP 0x02 /* Bus Master XFER Complete status */
+#define SCSICOMP 0x01 /* SCSI complete interrupt */
+#define TRM_S1040_DMA_INTEN 0xA4 /* DMA Interrupt Enable (R/W) */
+#define EN_SCSIINTR 0x01 /* Enable SCSI complete interrupt */
+#define TRM_S1040_DMA_CONFIG 0xA6 /* DMA Configuration (R/W) */
+#define DMA_ENHANCE 0x8000 /* Enable DMA enhance feature */
+#define TRM_S1040_DMA_XCNT 0xA8 /* DMA Transfer Counter (R/W) */
+#define TRM_S1040_DMA_CXCNT 0xAC /* DMA Current Transfer Counter (R) */
+#define TRM_S1040_DMA_XLOWADDR 0xB0 /* DMA Transfer Physical Low Address */
+#define TRM_S1040_DMA_XHIGHADDR 0xB4 /* DMA Transfer Physical High Address */
+
+#define TRM_S1040_GEN_CONTROL 0xD4 /* Global Control */
+#define EN_EEPROM 0x10 /* Enable EEPROM programming */
+#define AUTOTERM 0x04 /* Enable Auto SCSI terminator */
+#define LOW8TERM 0x02 /* Enable Lower 8 bit SCSI terminator */
+#define UP8TERM 0x01 /* Enable Upper 8 bit SCSI terminator */
+#define TRM_S1040_GEN_STATUS 0xD5 /* Global Status */
+#define GTIMEOUT 0x80 /* Global timer reach 0 */
+#define CON5068 0x10 /* External 50/68 pin connected */
+#define CON68 0x08 /* Internal 68 pin connected */
+#define CON50 0x04 /* Internal 50 pin connected */
+#define WIDESCSI 0x02 /* Wide SCSI card */
+#define TRM_S1040_GEN_NVRAM 0xD6 /* Serial NON-VOLATILE RAM port */
+#define NVR_BITOUT 0x08 /* Serial data out */
+#define NVR_BITIN 0x04 /* Serial data in */
+#define NVR_CLOCK 0x02 /* Serial clock */
+#define NVR_SELECT 0x01 /* Serial select */
+#define TRM_S1040_GEN_EDATA 0xD7 /* Parallel EEPROM data port */
+#define TRM_S1040_GEN_EADDRESS 0xD8 /* Parallel EEPROM address */
+#define TRM_S1040_GEN_TIMER 0xDB /* Global timer */
+
+int trm_Interrupt(void *);
+int trm_init(struct trm_softc *, int);
+
+#endif /* trm_h */
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 34201effde1..01fc09e530c 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.126 2002/02/14 18:13:58 mickey Exp $
+# $OpenBSD: files.pci,v 1.127 2002/02/18 01:55:30 krw Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -386,6 +386,10 @@ file dev/pci/cmpci.c cmpci
attach iha at pci with iha_pci
file dev/pci/iha_pci.c iha_pci
+# Tekram TRM-S1040 SCSI Cards (DC395U/UW/F,DC315/U)
+attach trm at pci with trm_pci
+file dev/pci/trm_pci.c trm_pci
+
# AMD Am53c974 PCscsi-PCI SCSI controllers
device pcscp: scsi, ncr53c9x
attach pcscp at pci
diff --git a/sys/dev/pci/trm_pci.c b/sys/dev/pci/trm_pci.c
new file mode 100644
index 00000000000..32d39e0d56d
--- /dev/null
+++ b/sys/dev/pci/trm_pci.c
@@ -0,0 +1,169 @@
+/* $OpenBSD: trm_pci.c,v 1.1 2002/02/18 01:55:30 krw Exp $
+ * ------------------------------------------------------------
+ * O.S : OpenBSD
+ * FILE NAME : trm_pci.c
+ * BY : Erich Chen (erich@tekram.com.tw)
+ * Description: Device Driver for Tekram DC395U/UW/F,DC315/U
+ * PCI SCSI Bus Master Host Adapter
+ * (SCSI chip set used Tekram ASIC TRM-S1040)
+ * (C)Copyright 1995-1999 Tekram Technology Co., Ltd.
+ * (C)Copyright 2001-2002 Ashley R. Martens and Kenneth R. Westerback
+ * ------------------------------------------------------------
+ * HISTORY:
+ *
+ * REV# DATE NAME DESCRIPTION
+ * 1.00 05/01/99 ERICH CHEN First released for NetBSD 1.4.x
+ * 1.01 00/00/00 MARTIN AKESSON Port to OpenBSD 2.8
+ * 1.02 Sep 19, 2001 ASHLEY MARTENS Cleanup and formatting
+ * ------------------------------------------------------------
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * ------------------------------------------------------------
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcivar.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/ic/trm.h>
+
+int trm_pci_probe (struct device *, void *, void *);
+void trm_pci_attach (struct device *, struct device *, void *);
+
+struct cfattach trm_pci_ca = {
+ sizeof(struct trm_softc),
+ trm_pci_probe,
+ trm_pci_attach,
+ NULL, /* Detach */
+ NULL, /* Activate */
+ NULL /* ZeroRef */
+};
+
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_pci_probe
+ * Purpose : Check the slots looking for a board we recognize.
+ * If we find one, note ti's address (slot) and call
+ * the actual probe routine to check it out.
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+int
+trm_pci_probe(struct device *parent, void *match, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TEKRAM2) {
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_TEKRAM2_DC3X5U:
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Function : trm_pci_attach
+ * Purpose :
+ * Inputs :
+ * ------------------------------------------------------------
+ */
+void
+trm_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+ bus_space_handle_t ioh;/* bus space handle */
+ pci_intr_handle_t ih;
+ struct trm_softc *sc = (void *)self;
+ bus_space_tag_t iot; /* bus space tag */
+ const char *intrstr;
+ pcireg_t command;
+ int unit;
+
+ unit = sc->sc_device.dv_unit;
+
+ /*
+ * These cards do not allow memory mapped accesses.
+ * pa_pc: chipset tag
+ * pa_tag: pci tag
+ */
+ command = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ command |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE;
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command);
+
+ if (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_TEKRAM2_DC3X5U)
+ return;
+
+ /*
+ * mask for get correct base address of pci IO port
+ */
+ if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0,
+ &iot, &ioh, NULL, NULL, 0) != 0) {
+ printf("%s: unable to map registers\n", sc->sc_device.dv_xname);
+ return;
+ }
+
+ /*
+ * test checksum of eeprom & initial "ACB" adapter control block
+ */
+ sc->sc_iotag = iot;
+ sc->sc_iohandle = ioh;
+ sc->sc_dmatag = pa->pa_dmat;
+
+ if (trm_init(sc, unit) != 0) {
+ printf("%s: trm_init failed", sc->sc_device.dv_xname);
+ return;
+ }
+
+ /*
+ * Map and establish interrupt
+ */
+ if (pci_intr_map(pa, &ih)) {
+ printf("%s: couldn't map interrupt\n", sc->sc_device.dv_xname);
+ return;
+ }
+ intrstr = pci_intr_string(pa->pa_pc, ih);
+
+ if (pci_intr_establish(pa->pa_pc, ih, IPL_BIO, trm_Interrupt, sc,
+ sc->sc_device.dv_xname) == NULL) {
+ printf("\n%s: couldn't establish interrupt", sc->sc_device.dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ } else {
+ if (intrstr != NULL)
+ printf(": %s\n", intrstr);
+
+ /* Tell SCSI layer about our SCSI bus */
+ config_found(&sc->sc_device, &sc->sc_link, scsiprint);
+ }
+}