summaryrefslogtreecommitdiffstats
path: root/sys/dev/stg
diff options
context:
space:
mode:
authornon <non@FreeBSD.org>2001-07-14 00:38:51 +0000
committernon <non@FreeBSD.org>2001-07-14 00:38:51 +0000
commite91272502526170cc4f62c2357a8b7d3ee9b2c27 (patch)
tree01f4c48045db66f0e363a543a36a88e13470d6c9 /sys/dev/stg
parenta67c5263965b3cce0db11089854bd6f3f56f2f8e (diff)
downloadFreeBSD-src-e91272502526170cc4f62c2357a8b7d3ee9b2c27.zip
FreeBSD-src-e91272502526170cc4f62c2357a8b7d3ee9b2c27.tar.gz
Catch up with NetBSD/pc98.
o Much cleanly separate NetBSD(XS) / FreeBSD(CAM) codes. o Improve tagged queing support (full QTAG). o Improve quirk support. o Improve parity error retry. o Impliment wide negotheation. o Cmd link support. o Add copyright of CAM part. o Change for CAM_NEW_TRAN_CODE. o Work around for buggy KME UJDCD450. o stg: add disconnet condition. o nsp: use suspend I/O. and more. I thank Honda-san. conf/options.pc98: add CT_USE_RELOCATE_OFFSET and CT_BUS_WEIGHT dev/{ct,ncv,nsp,stg}/*_{pccard,isa}.c: add splcam() before calling attach/detach functions. Tested by: bsd-nomads Obtained from: NetBSD/pc98
Diffstat (limited to 'sys/dev/stg')
-rw-r--r--sys/dev/stg/tmc18c30.c995
-rw-r--r--sys/dev/stg/tmc18c30_isa.c9
-rw-r--r--sys/dev/stg/tmc18c30_pccard.c9
-rw-r--r--sys/dev/stg/tmc18c30reg.h15
-rw-r--r--sys/dev/stg/tmc18c30var.h48
5 files changed, 696 insertions, 380 deletions
diff --git a/sys/dev/stg/tmc18c30.c b/sys/dev/stg/tmc18c30.c
index b331dd3..930aa40 100644
--- a/sys/dev/stg/tmc18c30.c
+++ b/sys/dev/stg/tmc18c30.c
@@ -1,15 +1,16 @@
/* $FreeBSD$ */
-/* $NecBSD: tmc18c30.c,v 1.28 1999/07/23 21:00:06 honda Exp $ */
+/* $NecBSD: tmc18c30.c,v 1.28.12.3 2001/06/19 04:35:48 honda Exp $ */
/* $NetBSD$ */
#define STG_DEBUG
#define STG_STATICS
+#define STG_IO_CONTROL_FLAGS (STG_FIFO_INTERRUPTS | STG_WAIT_FOR_SELECT)
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1996, 1997, 1998, 1999
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
- * Copyright (c) 1996, 1997, 1998, 1999
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
* Copyright (c) 1996, 1997, 1998, 1999
* Kouichi Matsuda. All rights reserved.
@@ -42,19 +43,16 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/disklabel.h>
#if defined(__FreeBSD__) && __FreeBSD_version >= 500001
#include <sys/bio.h>
-#endif
+#endif /* __FreeBSD__ */
#include <sys/buf.h>
#include <sys/queue.h>
#include <sys/malloc.h>
-#include <sys/device_port.h>
#include <sys/errno.h>
-#include <vm/vm.h>
-
#ifdef __NetBSD__
+#include <sys/device.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -73,8 +71,6 @@
#ifdef __FreeBSD__
#include <machine/clock.h>
-#define delay(time) DELAY(time)
-
#include <machine/cpu.h>
#include <machine/bus_pio.h>
#include <machine/bus.h>
@@ -106,10 +102,14 @@ struct stg_softc *stgdata[NSTG];
/* For the 512 fifo type: change below */
#define TMC18C30_FIFOSZ 0x800
-#define TMC18C30_FCB 1
-
+#define TMC18C30_FCBSZ 0x200
#define TMC18C50_FIFOSZ 0x2000
-#define TMC18C50_FCB 2
+#define TMC18C50_FCBSZ 0x400
+
+#define STG_MAX_DATA_SIZE (64 * 1024)
+#define STG_DELAY_MAX (2 * 1000 * 1000)
+#define STG_DELAY_INTERVAL (1)
+#define STG_DELAY_SELECT_POLLING_MAX (5 * 1000 * 1000)
/***************************************************
* PARAMS
@@ -120,47 +120,42 @@ struct stg_softc *stgdata[NSTG];
/***************************************************
* DEBUG
***************************************************/
-#ifndef DDB
-#define Debugger() panic("should call debugger here (tmc18c30.c)")
-#else /* ! DDB */
-#ifdef __FreeBSD__
-#define Debugger() Debugger("stg")
-#endif /* __FreeBSD__ */
-#endif
-
#ifdef STG_DEBUG
int stg_debug;
#endif /* STG_DEBUG */
#ifdef STG_STATICS
struct stg_statics {
+ int arbit_fail_0;
+ int arbit_fail_1;
int disconnect;
int reselect;
- int sprious_arbit_fail_0;
- int sprious_arbit_fail_1;
- int sprious_arbit_fail_2;
-} stg_statics[STG_NTARGETS];
+} stg_statics;
#endif /* STG_STATICS */
/***************************************************
- * ISA DEVICE STRUCTURE
+ * IO control flags
+ ***************************************************/
+#define STG_FIFO_INTERRUPTS 0x0001
+#define STG_WAIT_FOR_SELECT 0x0100
+
+int stg_io_control = STG_IO_CONTROL_FLAGS;
+
+/***************************************************
+ * DEVICE STRUCTURE
***************************************************/
extern struct cfdriver stg_cd;
/**************************************************************
* DECLARE
**************************************************************/
-#ifdef __NetBSD__
-extern int delaycount;
-#endif
-
/* static */
-static void stg_pio_read __P((struct stg_softc *, struct targ_info *));
-static void stg_pio_write __P((struct stg_softc *, struct targ_info *));
-static int stg_xfer __P((struct stg_softc *, u_int8_t *, int, int));
+static void stg_pio_read __P((struct stg_softc *, struct targ_info *, u_int));
+static void stg_pio_write __P((struct stg_softc *, struct targ_info *, u_int));
+static int stg_xfer __P((struct stg_softc *, u_int8_t *, int, int, int));
static int stg_msg __P((struct stg_softc *, struct targ_info *, u_int));
static int stg_reselected __P((struct stg_softc *));
-static __inline int stg_disconnected __P((struct stg_softc *, struct targ_info *));
+static int stg_disconnected __P((struct stg_softc *, struct targ_info *));
static __inline void stg_pdma_end __P((struct stg_softc *, struct targ_info *));
static int stghw_select_targ_wait __P((struct stg_softc *, int));
static int stghw_check __P((struct stg_softc *));
@@ -171,28 +166,35 @@ static int stg_world_start __P((struct stg_softc *, int));
static int stghw_start_selection __P((struct stg_softc *sc, struct slccb *));
static void stghw_bus_reset __P((struct stg_softc *));
static void stghw_attention __P((struct stg_softc *));
-static int stg_nexus __P((struct stg_softc *, struct targ_info *));
-static int stg_targ_init __P((struct stg_softc *, struct targ_info *));
+static int stg_target_nexus_establish __P((struct stg_softc *));
+static int stg_lun_nexus_establish __P((struct stg_softc *));
+static int stg_ccb_nexus_establish __P((struct stg_softc *));
+static int stg_targ_init __P((struct stg_softc *, struct targ_info *, int));
static __inline void stghw_bcr_write_1 __P((struct stg_softc *, u_int8_t));
+static int stg_timeout __P((struct stg_softc *));
+static void stg_selection_done_and_expect_msgout __P((struct stg_softc *));
struct scsi_low_funcs stgfuncs = {
SC_LOW_INIT_T stg_world_start,
SC_LOW_BUSRST_T stghw_bus_reset,
SC_LOW_TARG_INIT_T stg_targ_init,
+ SC_LOW_LUN_INIT_T NULL,
SC_LOW_SELECT_T stghw_start_selection,
- SC_LOW_NEXUS_T stg_nexus,
+ SC_LOW_NEXUS_T stg_lun_nexus_establish,
+ SC_LOW_NEXUS_T stg_ccb_nexus_establish,
SC_LOW_ATTEN_T stghw_attention,
SC_LOW_MSG_T stg_msg,
+ SC_LOW_TIMEOUT_T stg_timeout,
SC_LOW_POLL_T stgintr,
NULL,
};
/****************************************************
- * scsi low interface
+ * hwfuncs
****************************************************/
static __inline void
stghw_bcr_write_1(sc, bcv)
@@ -204,6 +206,101 @@ stghw_bcr_write_1(sc, bcv)
sc->sc_busimg = bcv;
}
+static int
+stghw_check(sc)
+ struct stg_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_int fcbsize, fcb;
+ u_int16_t lsb, msb;
+
+ lsb = bus_space_read_1(iot, ioh, tmc_idlsb);
+ msb = bus_space_read_1(iot, ioh, tmc_idmsb);
+ switch (msb << 8 | lsb)
+ {
+ case 0x6127:
+ /* TMCCHIP_1800 not supported. (it's my policy) */
+ sc->sc_chip = TMCCHIP_1800;
+ return EINVAL;
+
+ case 0x60e9:
+ if (bus_space_read_1(iot, ioh, tmc_cfg2) & 0x02)
+ {
+ sc->sc_chip = TMCCHIP_18C30;
+ sc->sc_fsz = TMC18C30_FIFOSZ;
+ fcbsize = TMC18C30_FCBSZ;
+ }
+ else
+ {
+ sc->sc_chip = TMCCHIP_18C50;
+ sc->sc_fsz = TMC18C50_FIFOSZ;
+ fcbsize = TMC18C50_FCBSZ;
+ }
+ break;
+
+ default:
+ sc->sc_chip = TMCCHIP_UNK;
+ return ENODEV;
+ }
+
+ sc->sc_fcRinit = FCTL_INTEN;
+ sc->sc_fcWinit = FCTL_PARENB | FCTL_INTEN;
+
+ if (slp->sl_cfgflags & CFG_NOATTEN)
+ sc->sc_imsg = 0;
+ else
+ sc->sc_imsg = BCTL_ATN;
+ sc->sc_busc = BCTL_BUSEN;
+
+ sc->sc_wthold = fcbsize + 256;
+ sc->sc_rthold = fcbsize - 256;
+ sc->sc_maxwsize = sc->sc_fsz;
+
+ fcb = fcbsize / (sc->sc_fsz / 16);
+ sc->sc_icinit = ICTL_CD | ICTL_SEL | ICTL_ARBIT | fcb;
+ return 0;
+}
+
+static void
+stghw_init(sc)
+ struct stg_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ bus_space_write_1(iot, ioh, tmc_ictl, 0);
+ stghw_bcr_write_1(sc, BCTL_BUSFREE);
+ bus_space_write_1(iot, ioh, tmc_fctl,
+ sc->sc_fcRinit | FCTL_CLRFIFO | FCTL_CLRINT);
+ bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
+ bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
+
+ bus_space_write_1(iot, ioh, tmc_ssctl, 0);
+}
+
+static int
+stg_targ_init(sc, ti, action)
+ struct stg_softc *sc;
+ struct targ_info *ti;
+ int action;
+{
+ struct stg_targ_info *sti = (void *) ti;
+
+ if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
+ {
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ ti->ti_maxsynch.period = 0;
+ ti->ti_maxsynch.offset = 0;
+ sti->sti_reg_synch = 0;
+ }
+ return 0;
+}
+
+/****************************************************
+ * scsi low interface
+ ****************************************************/
static void
stghw_attention(sc)
struct stg_softc *sc;
@@ -212,6 +309,7 @@ stghw_attention(sc)
sc->sc_busc |= BCTL_ATN;
sc->sc_busimg |= BCTL_ATN;
bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, sc->sc_busimg);
+ SCSI_LOW_DELAY(10);
}
static void
@@ -224,7 +322,7 @@ stghw_bus_reset(sc)
bus_space_write_1(iot, ioh, tmc_ictl, 0);
bus_space_write_1(iot, ioh, tmc_fctl, 0);
stghw_bcr_write_1(sc, BCTL_RST);
- delay(100000);
+ SCSI_LOW_DELAY(100000);
stghw_bcr_write_1(sc, BCTL_BUSFREE);
}
@@ -233,30 +331,24 @@ stghw_start_selection(sc, cb)
struct stg_softc *sc;
struct slccb *cb;
{
- struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct targ_info *ti = cb->ti;
- struct lun_info *li = ti->ti_li;
register u_int8_t stat;
int s;
- if (li->li_flags & SCSI_LOW_NOPARITY)
- sc->sc_fcRinit &= ~FCTL_PARENB;
- else
- sc->sc_fcRinit |= FCTL_PARENB;
-
+ sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
+ sc->sc_dataout_timeout = 0;
+ sc->sc_ubf_timeout = 0;
stghw_bcr_write_1(sc, BCTL_BUSFREE);
+ bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
s = splhigh();
- if (slp->sl_disc > 0)
+ stat = bus_space_read_1(iot, ioh, tmc_astat);
+ if ((stat & ASTAT_INT) != 0)
{
- stat = bus_space_read_1(iot, ioh, tmc_bstat);
- if (stat & (BSTAT_BSY | BSTAT_SEL | BSTAT_IO))
- {
- splx(s);
- return SCSI_LOW_START_FAIL;
- }
+ splx(s);
+ return SCSI_LOW_START_FAIL;
}
bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit);
@@ -274,22 +366,18 @@ stg_world_start(sc, fdone)
{
struct scsi_low_softc *slp = &sc->sc_sclow;
int error;
-#ifdef __FreeBSD__
- intrmask_t s;
-#endif
+
+ if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
+ sc->sc_fcRinit |= FCTL_PARENB;
+ else
+ sc->sc_fcRinit &= ~FCTL_PARENB;
if ((error = stghw_check(sc)) != 0)
return error;
-#ifdef __FreeBSD__
- s = splcam();
-#endif
stghw_init(sc);
scsi_low_bus_reset(slp);
stghw_init(sc);
-#ifdef __FreeBSD__
- splx(s);
-#endif
SOFT_INTR_REQUIRED(slp);
return 0;
@@ -301,11 +389,23 @@ stg_msg(sc, ti, msg)
struct targ_info *ti;
u_int msg;
{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
struct stg_targ_info *sti = (void *) ti;
u_int period, offset;
- if (msg != SCSI_LOW_MSG_SYNCH)
- return EINVAL;
+ if ((msg & SCSI_LOW_MSG_WIDE) != 0)
+ {
+ if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
+ {
+ ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
+ return EINVAL;
+ }
+ return 0;
+ }
+
+ if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
+ return 0;
period = ti->ti_maxsynch.period;
offset = ti->ti_maxsynch.offset;
@@ -324,93 +424,10 @@ stg_msg(sc, ti, msg)
sti->sti_reg_synch ++;
sti->sti_reg_synch |= SSCTL_SYNCHEN | SSCTL_FSYNCHEN;
}
+ bus_space_write_1(iot, ioh, tmc_ssctl, sti->sti_reg_synch);
return 0;
}
-/****************************************************
- * hwfuncs
- ****************************************************/
-static int
-stghw_check(sc)
- struct stg_softc *sc;
-{
- struct scsi_low_softc *slp = &sc->sc_sclow;
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
- u_int16_t lsb, msb;
-
- sc->sc_chip = TMCCHIP_UNK;
- sc->sc_fsz = TMC18C50_FIFOSZ;
- sc->sc_fcb = TMC18C50_FCB;
- sc->sc_fcsp = 0;
-
- sc->sc_fcRinit = FCTL_INTEN;
- sc->sc_fcWinit = FCTL_PARENB | FCTL_INTEN;
-
- if (slp->sl_cfgflags & CFG_NOATTEN)
- sc->sc_imsg = 0;
- else
- sc->sc_imsg = BCTL_ATN;
- sc->sc_busc = BCTL_BUSEN;
-
- lsb = bus_space_read_1(iot, ioh, tmc_idlsb);
- msb = bus_space_read_1(iot, ioh, tmc_idmsb);
- switch (msb << 8 | lsb)
- {
- case 0x6127:
- /* TMCCHIP_1800 not supported. (it's my policy) */
- sc->sc_chip = TMCCHIP_1800;
- return EINVAL;
-
- case 0x60e9:
- sc->sc_chip = TMCCHIP_18C50;
- sc->sc_fcsp |= FCTL_CLRINT;
- if (bus_space_read_1(iot, ioh, tmc_cfg2) & 0x02)
- {
- sc->sc_chip = TMCCHIP_18C30;
- sc->sc_fsz = TMC18C30_FIFOSZ;
- sc->sc_fcb = TMC18C30_FCB;
- }
- break;
-
- default:
- return ENODEV;
- }
-
- sc->sc_icinit = ICTL_ALLINT | sc->sc_fcb;
- return 0;
-}
-
-static void
-stghw_init(sc)
- struct stg_softc *sc;
-{
- bus_space_tag_t iot = sc->sc_iot;
- bus_space_handle_t ioh = sc->sc_ioh;
-
- bus_space_write_1(iot, ioh, tmc_ictl, 0);
- stghw_bcr_write_1(sc, BCTL_BUSFREE);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcsp | sc->sc_fcRinit |
- FCTL_CLRFIFO);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
- bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
-
- bus_space_write_1(iot, ioh, tmc_ssctl, 0);
-}
-
-static int
-stg_targ_init(sc, ti)
- struct stg_softc *sc;
- struct targ_info *ti;
-{
- struct stg_targ_info *sti = (void *) ti;
-
- ti->ti_maxsynch.period = 0;
- ti->ti_maxsynch.offset = 8;
- sti->sti_reg_synch = 0;
- return 0;
-}
-
/**************************************************************
* General probe attach
**************************************************************/
@@ -456,24 +473,15 @@ stgattachsubr(sc)
printf("\n");
-#ifdef __FreeBSD__
- sc->sc_wc = 0x2000 * 2000; /* XXX need calibration */
-#else
- sc->sc_wc = delaycount * 2000; /* 2 sec */
-#endif
sc->sc_idbit = (1 << slp->sl_hostid);
slp->sl_funcs = &stgfuncs;
+ sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
+ slp->sl_flags |= HW_READ_PADDING;
slp->sl_cfgflags |= CFG_ASYNC; /* XXX */
- if (stghw_check(sc) != 0)
- {
- printf("stg: hardware missing\n");
- return;
- }
-
- (void) scsi_low_attach(slp, 2, STG_NTARGETS, STG_NLUNS,
- sizeof(struct stg_targ_info));
+ (void) scsi_low_attach(slp, 0, STG_NTARGETS, STG_NLUNS,
+ sizeof(struct stg_targ_info), 0);
}
/**************************************************************
@@ -487,10 +495,18 @@ stg_pdma_end(sc, ti)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct slccb *cb = ti->ti_nexus;
+ struct slccb *cb = slp->sl_Qnexus;
u_int len, tres;
slp->sl_flags &= ~HW_PDMASTART;
+ sc->sc_icinit &= ~ICTL_FIFO;
+ sc->sc_dataout_timeout = 0;
+
+ if (cb == NULL)
+ {
+ slp->sl_error |= PDMAERR;
+ goto out;
+ }
if (ti->ti_phase == PH_DATA)
{
@@ -523,6 +539,7 @@ stg_pdma_end(sc, ti)
slp->sl_xname, len);
}
}
+ scsi_low_data_finish(slp);
}
else
{
@@ -531,41 +548,84 @@ stg_pdma_end(sc, ti)
slp->sl_error |= PDMAERR;
}
+out:
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
}
static void
-stg_pio_read(sc, ti)
+stg_pio_read(sc, ti, thold)
struct stg_softc *sc;
struct targ_info *ti;
+ u_int thold;
{
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct sc_p *sp = &slp->sl_scp;
- int tout = sc->sc_wc;
+ int s, tout;
u_int res;
u_int8_t stat;
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_FIFOEN);
+ if ((slp->sl_flags & HW_PDMASTART) == 0)
+ {
+ bus_space_write_1(iot, ioh, tmc_fctl,
+ sc->sc_fcRinit | FCTL_FIFOEN);
+ slp->sl_flags |= HW_PDMASTART;
+ }
- slp->sl_flags |= HW_PDMASTART;
- while (sp->scp_datalen > 0 && tout -- > 0)
+ tout = sc->sc_tmaxcnt;
+ while (tout -- > 0)
{
- res = bus_space_read_2(iot, ioh, tmc_fdcnt);
- if (res == 0)
+ if (thold > 0)
+ {
+ s = splhigh();
+ res = bus_space_read_2(iot, ioh, tmc_fdcnt);
+ if (res < thold)
+ {
+ bus_space_write_1(iot, ioh, tmc_ictl,
+ sc->sc_icinit);
+ splx(s);
+ break;
+ }
+ splx(s);
+ }
+ else
{
stat = bus_space_read_1(iot, ioh, tmc_bstat);
- if ((stat & BSTAT_PHMASK) == BSTAT_IO)
+ res = bus_space_read_2(iot, ioh, tmc_fdcnt);
+ if (res == 0)
+ {
+ if ((stat & PHASE_MASK) != DATA_IN_PHASE)
+ break;
+ if (sp->scp_datalen <= 0)
+ break;
+ SCSI_LOW_DELAY(1);
continue;
- break; /* phase mismatch */
+ }
}
- /* XXX */
+ /* The assumtion res != 0 is valid here */
if (res > sp->scp_datalen)
{
+ if (res == (u_int) -1)
+ break;
+
slp->sl_error |= PDMAERR;
- break;
+ if ((slp->sl_flags & HW_READ_PADDING) == 0)
+ {
+ printf("%s: read padding required\n",
+ slp->sl_xname);
+ break;
+ }
+
+ sp->scp_datalen = 0;
+ if (res > STG_MAX_DATA_SIZE)
+ res = STG_MAX_DATA_SIZE;
+ while (res -- > 0)
+ {
+ (void) bus_space_read_1(iot, ioh, tmc_rfifo);
+ }
+ continue;
}
sp->scp_datalen -= res;
@@ -582,40 +642,74 @@ stg_pio_read(sc, ti)
}
if (tout <= 0)
- printf("%s pio read timeout\n", slp->sl_xname);
+ printf("%s: pio read timeout\n", slp->sl_xname);
}
-#define WFIFO_CRIT 0x100
-
static void
-stg_pio_write(sc, ti)
+stg_pio_write(sc, ti, thold)
struct stg_softc *sc;
struct targ_info *ti;
+ u_int thold;
{
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
struct sc_p *sp = &slp->sl_scp;
u_int res;
- int tout = sc->sc_wc;
+ int s, tout;
register u_int8_t stat;
- stat = sc->sc_fcWinit | FCTL_FIFOEN | FCTL_FIFOW;
- bus_space_write_1(iot, ioh, tmc_fctl, stat | FCTL_CLRFIFO);
- bus_space_write_1(iot, ioh, tmc_fctl, stat);
+ if ((slp->sl_flags & HW_PDMASTART) == 0)
+ {
+ stat = sc->sc_fcWinit | FCTL_FIFOEN | FCTL_FIFOW;
+ bus_space_write_1(iot, ioh, tmc_fctl, stat | FCTL_CLRFIFO);
+ bus_space_write_1(iot, ioh, tmc_fctl, stat);
+ slp->sl_flags |= HW_PDMASTART;
+ }
- slp->sl_flags |= HW_PDMASTART;
- while (sp->scp_datalen > 0 && tout -- > 0)
+ tout = sc->sc_tmaxcnt;
+ while (tout -- > 0)
{
stat = bus_space_read_1(iot, ioh, tmc_bstat);
- if ((stat & BSTAT_PHMASK) != 0)
+ if ((stat & PHASE_MASK) != DATA_OUT_PHASE)
break;
- if (bus_space_read_2(iot, ioh, tmc_fdcnt) >= WFIFO_CRIT)
- continue;
+ if (sp->scp_datalen <= 0)
+ {
+ if (sc->sc_dataout_timeout == 0)
+ sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
+ break;
+ }
+
+ if (thold > 0)
+ {
+ s = splhigh();
+ res = bus_space_read_2(iot, ioh, tmc_fdcnt);
+ if (res > thold)
+ {
+ bus_space_write_1(iot, ioh, tmc_ictl,
+ sc->sc_icinit);
+ splx(s);
+ break;
+ }
+ splx(s);
+ }
+ else
+ {
+ res = bus_space_read_2(iot, ioh, tmc_fdcnt);
+ if (res > sc->sc_maxwsize / 2)
+ {
+ SCSI_LOW_DELAY(1);
+ continue;
+ }
+ }
+
+ if (res == (u_int) -1)
+ break;
+ res = sc->sc_maxwsize - res;
+ if (res > sp->scp_datalen)
+ res = sp->scp_datalen;
- res = (sp->scp_datalen > WFIFO_CRIT) ?
- WFIFO_CRIT : sp->scp_datalen;
sp->scp_datalen -= res;
if ((res & 0x1) != 0)
{
@@ -630,7 +724,7 @@ stg_pio_write(sc, ti)
}
if (tout <= 0)
- printf("%s pio write timeout\n", slp->sl_xname);
+ printf("%s: pio write timeout\n", slp->sl_xname);
}
static int
@@ -642,23 +736,22 @@ stg_negate_signal(sc, mask, s)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- int wc = (sc->sc_wc >> 2);
+ int wc;
u_int8_t regv;
- do
+ for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++)
{
regv = bus_space_read_1(bst, bsh, tmc_bstat);
- if (regv == 0xff)
- return EIO;
- }
- while ((regv & mask) != 0 && (-- wc) > 0);
+ if (regv == (u_int8_t) -1)
+ return -1;
+ if ((regv & mask) == 0)
+ return 1;
- if (wc <= 0)
- {
- printf("%s: %s singal off timeout \n", slp->sl_xname, s);
- return EIO;
+ SCSI_LOW_DELAY(STG_DELAY_INTERVAL);
}
- return 0;
+
+ printf("%s: %s stg_negate_signal timeout\n", slp->sl_xname, s);
+ return -1;
}
static int
@@ -669,49 +762,39 @@ stg_expect_signal(sc, phase, mask)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t bst = sc->sc_iot;
bus_space_handle_t bsh = sc->sc_ioh;
- int wc = (sc->sc_wc >> 2);
- int rv = -1;
+ int wc;
u_int8_t ph;
- phase &= BSTAT_PHMASK;
- do
+ phase &= PHASE_MASK;
+ for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++)
{
ph = bus_space_read_1(bst, bsh, tmc_bstat);
- if (ph == 0xff) {
- rv = -1;
- break;
- }
- if ((ph & BSTAT_PHMASK) != phase) {
- rv = 0;
- break;
- }
- if ((ph & mask) != 0) {
- rv = 1;
- break;
- }
- }
- while (wc -- > 0);
+ if (ph == (u_int8_t) -1)
+ return -1;
+ if ((ph & PHASE_MASK) != phase)
+ return 0;
+ if ((ph & mask) != 0)
+ return 1;
- if (wc <= 0) {
- printf("%s: stg_expect_signal timeout\n", slp->sl_xname);
- rv = -1;
+ SCSI_LOW_DELAY(STG_DELAY_INTERVAL);
}
- return rv;
+
+ printf("%s: stg_expect_signal timeout\n", slp->sl_xname);
+ return -1;
}
static int
-stg_xfer(sc, buf, len, phase)
+stg_xfer(sc, buf, len, phase, clear_atn)
struct stg_softc *sc;
u_int8_t *buf;
int len;
int phase;
+ int clear_atn;
{
- struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- int rv, ptr, atn;
+ int rv, ptr;
- atn = (scsi_low_is_msgout_continue(slp->sl_nexus) != 0);
if (phase & BSTAT_IO)
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
else
@@ -723,10 +806,11 @@ stg_xfer(sc, buf, len, phase)
if (rv <= 0)
goto bad;
- if (len == 1 && atn == 0)
+ if (len == 1 && clear_atn != 0)
{
sc->sc_busc &= ~BCTL_ATN;
stghw_bcr_write_1(sc, sc->sc_busc);
+ SCSI_LOW_DEASSERT_ATN(&sc->sc_sclow);
}
if (phase & BSTAT_IO)
@@ -737,6 +821,7 @@ stg_xfer(sc, buf, len, phase)
{
bus_space_write_1(iot, ioh, tmc_wdata, buf[ptr ++]);
}
+
stg_negate_signal(sc, BSTAT_ACK, "xfer<ACK>");
}
@@ -755,44 +840,83 @@ stg_reselected(sc)
struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct targ_info *ti;
+ int tout;
u_int sid;
+ u_int8_t regv;
if (slp->sl_selid != NULL)
{
/* XXX:
* Selection vs Reselection conflicts.
*/
-#ifdef STG_STATICS
- stg_statics[slp->sl_selid->ti_id].sprious_arbit_fail_0 ++;
-#endif /* STG_STATICS */
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, BCTL_BUSFREE);
}
+ else if (slp->sl_Tnexus != NULL)
+ {
+ printf("%s: unexpected termination\n", slp->sl_xname);
+ stg_disconnected(sc, slp->sl_Tnexus);
+ }
/* XXX:
* We should ack the reselection as soon as possible,
* becuase the target would abort the current reselection seq
* due to reselection timeout.
*/
+ tout = STG_DELAY_SELECT_POLLING_MAX;
+ while (tout -- > 0)
+ {
+ regv = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) ==
+ (BSTAT_IO | BSTAT_SEL))
+ {
+ SCSI_LOW_DELAY(1);
+ regv = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) ==
+ (BSTAT_IO | BSTAT_SEL))
+ goto reselect_start;
+ }
+ SCSI_LOW_DELAY(1);
+ }
+ printf("%s: reselction timeout I\n", slp->sl_xname);
+ return EJUSTRETURN;
+
+reselect_start:
sid = (u_int) bus_space_read_1(iot, ioh, tmc_scsiid);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcsp |
- sc->sc_fcRinit | FCTL_CLRFIFO);
+ if ((sid & sc->sc_idbit) == 0)
+ {
+ /* not us */
+ return EJUSTRETURN;
+ }
+
+ bus_space_write_1(iot, ioh, tmc_fctl,
+ sc->sc_fcRinit | FCTL_CLRFIFO | FCTL_CLRINT);
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, sc->sc_busc | BCTL_BSY);
+ while (tout -- > 0)
+ {
+ regv = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((regv & (BSTAT_SEL | BSTAT_BSY)) == BSTAT_BSY)
+ goto reselected;
+ SCSI_LOW_DELAY(1);
+ }
+ printf("%s: reselction timeout II\n", slp->sl_xname);
+ return EJUSTRETURN;
+
+reselected:
sid &= ~sc->sc_idbit;
sid = ffs(sid) - 1;
- if ((ti = scsi_low_reselected(slp, sid)) == NULL)
+ if (scsi_low_reselected(slp, sid) == NULL)
return EJUSTRETURN;
#ifdef STG_STATICS
- stg_statics[sid].reselect ++;
+ stg_statics.reselect ++;
#endif /* STG_STATICS */
return EJUSTRETURN;
}
-static __inline int
+static int
stg_disconnected(sc, ti)
struct stg_softc *sc;
struct targ_info *ti;
@@ -805,12 +929,13 @@ stg_disconnected(sc, ti)
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO);
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, BCTL_BUSFREE);
- sc->sc_fcRinit &= ~FCTL_PARENB;
+ sc->sc_icinit &= ~ICTL_FIFO;
sc->sc_busc &= ~BCTL_ATN;
+ sc->sc_dataout_timeout = 0;
+ sc->sc_ubf_timeout = 0;
#ifdef STG_STATICS
- if (slp->sl_msgphase == MSGPH_DISC)
- stg_statics[ti->ti_id].disconnect ++;
+ stg_statics.disconnect ++;
#endif /* STG_STATICS */
scsi_low_disconnected(slp, ti);
return 1;
@@ -820,51 +945,81 @@ stg_disconnected(sc, ti)
* SEQUENCER
**************************************************************/
static int
-stg_nexus(sc, ti)
+stg_target_nexus_establish(sc)
struct stg_softc *sc;
- struct targ_info *ti;
{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- struct lun_info *li = ti->ti_li;
+ struct targ_info *ti = slp->sl_Tnexus;
struct stg_targ_info *sti = (void *) ti;
- if (li->li_flags & SCSI_LOW_NOPARITY)
- sc->sc_fcRinit &= ~FCTL_PARENB;
- else
- sc->sc_fcRinit |= FCTL_PARENB;
-
bus_space_write_1(iot, ioh, tmc_ssctl, sti->sti_reg_synch);
+ if ((stg_io_control & STG_FIFO_INTERRUPTS) != 0)
+ {
+ sc->sc_icinit |= ICTL_FIFO;
+ }
return 0;
}
static int
-stghw_select_targ_wait(sc, id)
+stg_lun_nexus_establish(sc)
struct stg_softc *sc;
- int id;
+{
+
+ return 0;
+}
+
+static int
+stg_ccb_nexus_establish(sc)
+ struct stg_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ struct slccb *cb = slp->sl_Qnexus;
+
+ sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
+ return 0;
+}
+
+#define STGHW_SELECT_INTERVAL 10
+
+static int
+stghw_select_targ_wait(sc, mu)
+ struct stg_softc *sc;
+ int mu;
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
- int wc, error = EIO;
- bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit | (1 << id));
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit & (~FCTL_INTEN));
- stghw_bcr_write_1(sc, sc->sc_busc | sc->sc_imsg | BCTL_SEL);
-
- for (wc = 50000; wc; wc--)
+ mu = mu / STGHW_SELECT_INTERVAL;
+ while (mu -- > 0)
{
- if (bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY)
+ if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) == 0)
{
- error = 0;
- break;
+ SCSI_LOW_DELAY(STGHW_SELECT_INTERVAL);
+ continue;
+ }
+ SCSI_LOW_DELAY(1);
+ if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) != 0)
+ {
+ return 0;
}
-
- delay(1);
}
+ return ENXIO;
+}
+
+static void
+stg_selection_done_and_expect_msgout(sc)
+ struct stg_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO);
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
- return error;
+ stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc);
+ SCSI_LOW_ASSERT_ATN(slp);
}
int
@@ -878,7 +1033,8 @@ stgintr(arg)
struct targ_info *ti;
struct physio_proc *pp;
struct buf *bp;
- int len;
+ u_int derror, flags;
+ int len, s;
u_int8_t status, astatus, regv;
/*******************************************
@@ -890,14 +1046,16 @@ stgintr(arg)
astatus = bus_space_read_1(iot, ioh, tmc_astat);
status = bus_space_read_1(iot, ioh, tmc_bstat);
- if ((astatus & ASTAT_STATMASK) == 0)
+ if ((astatus & ASTAT_STATMASK) == 0 || astatus == (u_int8_t) -1)
return 0;
+ bus_space_write_1(iot, ioh, tmc_ictl, 0);
if (astatus & ASTAT_SCSIRST)
{
bus_space_write_1(iot, ioh, tmc_fctl,
sc->sc_fcRinit | FCTL_CLRFIFO);
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
+ bus_space_write_1(iot, ioh, tmc_ictl, 0);
scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT,
"bus reset (power off?)");
@@ -911,10 +1069,12 @@ stgintr(arg)
if (stg_debug)
{
scsi_low_print(slp, NULL);
- printf("%s st %x ist %x\n\n", slp->sl_xname,
+ printf("%s: st %x ist %x\n\n", slp->sl_xname,
status, astatus);
+#ifdef DDB
if (stg_debug > 1)
- Debugger();
+ SCSI_LOW_DEBUGGER("stg");
+#endif /* DDB */
}
#endif /* STG_DEBUG */
@@ -924,34 +1084,20 @@ stgintr(arg)
if ((status & RESEL_PHASE_MASK)== PHASE_RESELECTED)
{
if (stg_reselected(sc) == EJUSTRETURN)
- return 1;
+ goto out;
}
- if ((ti = slp->sl_nexus) == NULL)
- {
- status = bus_space_read_1(iot, ioh, tmc_bstat);
- if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
- return 1;
-
- /* XXX:
- * Some scsi devices overrun scsi phase.
- */
- if (stg_reselected(sc) == EJUSTRETURN)
- {
-#ifdef STG_STATICS
- if ((ti = slp->sl_nexus) != NULL)
- stg_statics[ti->ti_id].sprious_arbit_fail_1 ++;
-#endif /* STG_STATICS */
- return 1;
- }
- }
+ if ((ti = slp->sl_Tnexus) == NULL)
+ return 0;
+ derror = 0;
if ((astatus & ASTAT_PARERR) != 0 && ti->ti_phase != PH_ARBSTART &&
(sc->sc_fcRinit & FCTL_PARENB) != 0)
{
slp->sl_error |= PARITYERR;
- if (ti->ti_phase == PH_MSGIN)
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 1);
+ derror = SCSI_LOW_DATA_PE;
+ if ((status & PHASE_MASK) == MESSAGE_IN_PHASE)
+ scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
else
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1);
}
@@ -963,7 +1109,12 @@ stgintr(arg)
{
case PH_ARBSTART:
if ((astatus & ASTAT_ARBIT) == 0)
+ {
+#ifdef STG_STATICS
+ stg_statics.arbit_fail_0 ++;
+#endif /* STG_STATICS */
goto arb_fail;
+ }
status = bus_space_read_1(iot, ioh, tmc_bstat);
if ((status & BSTAT_IO) != 0)
@@ -972,167 +1123,311 @@ stgintr(arg)
* Selection vs Reselection conflicts.
*/
#ifdef STG_STATICS
- stg_statics[ti->ti_id].sprious_arbit_fail_2 ++;
+ stg_statics.arbit_fail_1 ++;
#endif /* STG_STATICS */
arb_fail:
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, BCTL_BUSFREE);
- SCSI_LOW_SETUP_PHASE(ti, PH_NULL);
- scsi_low_clear_nexus(slp, ti);
- return 1;
+ scsi_low_arbit_fail(slp, slp->sl_Qnexus);
+ goto out;
}
/*
* selection assert start.
*/
SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
- scsi_low_arbit_win(slp, ti);
-#ifdef STG_ALT_SELECTION
+ scsi_low_arbit_win(slp);
+
+ s = splhigh();
bus_space_write_1(iot, ioh, tmc_scsiid,
sc->sc_idbit | (1 << ti->ti_id));
- /* assert busy */
- stghw_bcr_write_1(sc, sc->sc_imsg | BCTL_BSY | sc->sc_busc);
- /* arb flag clear */
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit);
- /* assert sel */
- stghw_bcr_write_1(sc, sc->sc_imsg | BCTL_BSY | sc->sc_busc | BCTL_SEL);
- delay(3);
- /* deassert busy */
stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL);
-#else /* !STG_ALT_SELECTION */
- bus_space_write_1(iot, ioh, tmc_scsiid,
- sc->sc_idbit | (1 << ti->ti_id));
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit);
- stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL);
-#endif /* !STG_ALT_SELECTION */
- return 1;
+ if ((stg_io_control & STG_WAIT_FOR_SELECT) != 0)
+ {
+ /* selection abort delay 200 + 100 micro sec */
+ if (stghw_select_targ_wait(sc, 300) == 0)
+ {
+ SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
+ stg_selection_done_and_expect_msgout(sc);
+ }
+ }
+ splx(s);
+ goto out;
case PH_SELSTART:
if ((status & BSTAT_BSY) == 0)
{
- if (stghw_select_targ_wait(sc, ti->ti_id) != 0)
+ /* selection timeout delay 250 ms */
+ if (stghw_select_targ_wait(sc, 250 * 1000) != 0)
{
- return stg_disconnected(sc, ti);
+ stg_disconnected(sc, ti);
+ goto out;
}
}
- /*
- * attention assert.
- */
SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit |
- FCTL_CLRFIFO);
- bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
- stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc);
- SCSI_LOW_TARGET_ASSERT_ATN(ti);
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
- return 1;
+ stg_selection_done_and_expect_msgout(sc);
+ goto out;
+
+ case PH_SELECTED:
+ if ((status & BSTAT_REQ) == 0)
+ goto out;
+ stg_target_nexus_establish(sc);
+ break;
case PH_RESEL:
+ if ((status & BSTAT_REQ) == 0)
+ goto out;
+
/* clear a busy line */
bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
stghw_bcr_write_1(sc, sc->sc_busc);
+ stg_target_nexus_establish(sc);
if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
{
+ printf("%s: unexpected phase after reselect\n",
+ slp->sl_xname);
+ slp->sl_error |= FATALIO;
scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
- return 1;
+ goto out;
}
break;
}
/*******************************************
- * scsi seq
+ * data phase
*******************************************/
- if (slp->sl_flags & HW_PDMASTART)
+ if ((slp->sl_flags & HW_PDMASTART) && STG_IS_PHASE_DATA(status) == 0)
+ {
+ if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
+ stg_pio_read(sc, ti, 0);
+
stg_pdma_end(sc, ti);
+ }
+ /*******************************************
+ * scsi seq
+ *******************************************/
switch (status & PHASE_MASK)
{
case COMMAND_PHASE:
+ if (stg_expect_signal(sc, COMMAND_PHASE, BSTAT_REQ) <= 0)
+ break;
+
SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
if (scsi_low_cmd(slp, ti) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
- if (stg_xfer(sc, slp->sl_scp.scp_cmd,
- slp->sl_scp.scp_cmdlen, COMMAND_PHASE) != 0)
+ if (stg_xfer(sc, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen,
+ COMMAND_PHASE, 0) != 0)
{
- printf("%s: MSGOUT short\n", slp->sl_xname);
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_RESET, 0);
+ printf("%s: CMDOUT short\n", slp->sl_xname);
}
break;
case DATA_OUT_PHASE:
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
pp = physio_proc_enter(bp);
- stg_pio_write(sc, ti);
+ if ((sc->sc_icinit & ICTL_FIFO) != 0)
+ stg_pio_write(sc, ti, sc->sc_wthold);
+ else
+ stg_pio_write(sc, ti, 0);
physio_proc_leave(pp);
break;
case DATA_IN_PHASE:
SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
- break;
+ {
+ scsi_low_attention(slp);
+ }
pp = physio_proc_enter(bp);
- stg_pio_read(sc, ti);
+ if ((sc->sc_icinit & ICTL_FIFO) != 0)
+ stg_pio_read(sc, ti, sc->sc_rthold);
+ else
+ stg_pio_read(sc, ti, 0);
physio_proc_leave(pp);
break;
case STATUS_PHASE:
+ regv = stg_expect_signal(sc, STATUS_PHASE, BSTAT_REQ);
+ if (regv <= 0)
+ break;
+
SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
- ti->ti_status = bus_space_read_1(iot, ioh, tmc_rdata);
+ regv = bus_space_read_1(iot, ioh, tmc_sdna);
+ if (scsi_low_statusin(slp, ti, regv | derror) != 0)
+ {
+ scsi_low_attention(slp);
+ }
+ if (regv != bus_space_read_1(iot, ioh, tmc_rdata))
+ {
+ printf("%s: STATIN: data mismatch\n", slp->sl_xname);
+ }
+ stg_negate_signal(sc, BSTAT_ACK, "statin<ACK>");
break;
case MESSAGE_OUT_PHASE:
+ if (stg_expect_signal(sc, MESSAGE_OUT_PHASE, BSTAT_REQ) <= 0)
+ break;
+
SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
- len = scsi_low_msgout(slp, ti);
- if (stg_xfer(sc, ti->ti_msgoutstr, len, MESSAGE_OUT_PHASE))
+ flags = (ti->ti_ophase != ti->ti_phase) ?
+ SCSI_LOW_MSGOUT_INIT : 0;
+ len = scsi_low_msgout(slp, ti, flags);
+
+ if (len > 1 && slp->sl_atten == 0)
+ {
+ scsi_low_attention(slp);
+ }
+
+ if (stg_xfer(sc, ti->ti_msgoutstr, len, MESSAGE_OUT_PHASE,
+ slp->sl_clear_atten) != 0)
{
- scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_RESET, 0);
printf("%s: MSGOUT short\n", slp->sl_xname);
}
+ else
+ {
+ if (slp->sl_msgphase >= MSGPH_ABORT)
+ {
+ stg_disconnected(sc, ti);
+ }
+ }
break;
case MESSAGE_IN_PHASE:
+ /* confirm phase and req signal */
+ if (stg_expect_signal(sc, MESSAGE_IN_PHASE, BSTAT_REQ) <= 0)
+ break;
+
SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
- /* confirm REQ signal */
- regv = stg_expect_signal(sc, MESSAGE_IN_PHASE, BSTAT_REQ);
- if (regv <= 0)
- {
- printf("%s: MSGIN: no req\n", slp->sl_xname);
- break;
- }
/* read data with NOACK */
- regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, tmc_sdna);
+ regv = bus_space_read_1(iot, ioh, tmc_sdna);
- scsi_low_msgin(slp, ti, regv);
+ if (scsi_low_msgin(slp, ti, derror | regv) == 0)
+ {
+ if (scsi_low_is_msgout_continue(ti, 0) != 0)
+ {
+ scsi_low_attention(slp);
+ }
+ }
/* read data with ACK */
- if (regv != bus_space_read_1(sc->sc_iot, sc->sc_ioh, tmc_rdata))
+ if (regv != bus_space_read_1(iot, ioh, tmc_rdata))
{
printf("%s: MSGIN: data mismatch\n", slp->sl_xname);
}
- if (slp->sl_msgphase != 0)
+ /* wait for the ack negated */
+ stg_negate_signal(sc, BSTAT_ACK, "msgin<ACK>");
+
+ if (slp->sl_msgphase != 0 && slp->sl_msgphase < MSGPH_ABORT)
{
- stg_negate_signal(sc, BSTAT_ACK, "discon<ACK>");
- return stg_disconnected(sc, ti);
+ stg_disconnected(sc, ti);
}
break;
case BUSFREE_PHASE:
- printf("%s unexpected disconnection\n", slp->sl_xname);
- return stg_disconnected(sc, ti);
+ printf("%s: unexpected disconnect\n", slp->sl_xname);
+ stg_disconnected(sc, ti);
+ break;
default:
- printf("%s unknown phase bus %x intr %x\n",
+ slp->sl_error |= FATALIO;
+ printf("%s: unknown phase bus %x intr %x\n",
slp->sl_xname, status, astatus);
break;
}
+out:
+ bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
return 1;
}
+
+static int
+stg_timeout(sc)
+ struct stg_softc *sc;
+{
+ struct scsi_low_softc *slp = &sc->sc_sclow;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int tout, count;
+ u_int8_t status;
+
+ if (slp->sl_Tnexus == NULL)
+ return 0;
+
+ status = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((status & PHASE_MASK) == 0)
+ {
+ if (sc->sc_ubf_timeout ++ == 0)
+ return 0;
+
+ printf("%s: unexpected bus free detected\n", slp->sl_xname);
+ slp->sl_error |= FATALIO;
+ scsi_low_print(slp, slp->sl_Tnexus);
+ stg_disconnected(sc, slp->sl_Tnexus);
+ return 0;
+ }
+
+ switch (status & PHASE_MASK)
+ {
+ case DATA_OUT_PHASE:
+ if (sc->sc_dataout_timeout == 0)
+ break;
+ if ((status & BSTAT_REQ) == 0)
+ break;
+ if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0)
+ break;
+ if ((-- sc->sc_dataout_timeout) > 0)
+ break;
+
+ slp->sl_error |= PDMAERR;
+ if ((slp->sl_flags & HW_WRITE_PADDING) == 0)
+ {
+ printf("%s: write padding required\n",
+ slp->sl_xname);
+ break;
+ }
+
+ bus_space_write_1(iot, ioh, tmc_ictl, 0);
+
+ tout = STG_DELAY_MAX;
+ while (tout --)
+ {
+ status = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((status & PHASE_MASK) != DATA_OUT_PHASE)
+ break;
+
+ if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0)
+ {
+ SCSI_LOW_DELAY(1);
+ continue;
+ }
+
+ for (count = sc->sc_maxwsize; count > 0; count --)
+ bus_space_write_1(iot, ioh, tmc_wfifo, 0);
+ }
+
+ status = bus_space_read_1(iot, ioh, tmc_bstat);
+ if ((status & PHASE_MASK) == DATA_OUT_PHASE)
+ sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
+
+ bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/sys/dev/stg/tmc18c30_isa.c b/sys/dev/stg/tmc18c30_isa.c
index 53df893..21e9361 100644
--- a/sys/dev/stg/tmc18c30_isa.c
+++ b/sys/dev/stg/tmc18c30_isa.c
@@ -237,10 +237,13 @@ static void
stg_isa_unload(device_t devi)
{
struct stg_softc *sc = device_get_softc(devi);
+ intrmask_t s;
printf("%s: unload\n",sc->sc_sclow.sl_xname);
+ s = splcam();
scsi_low_deactivate((struct scsi_low_softc *)sc);
scsi_low_dettach(&sc->sc_sclow);
+ splx(s);
}
static int
@@ -263,7 +266,7 @@ stgattach(device_t devi)
struct scsi_low_softc *slp;
u_int32_t flags = device_get_flags(devi);
u_int iobase = bus_get_resource_start(devi, SYS_RES_IOPORT, 0);
-
+ intrmask_t s;
char dvname[16];
strcpy(dvname,"stg");
@@ -288,9 +291,9 @@ stgattach(device_t devi)
slp->sl_hostid = STG_HOSTID;
slp->sl_cfgflags = flags;
+ s = splcam();
stgattachsubr(sc);
-
- sc->sc_ih = stgintr;
+ splx(s);
return(STGIOSZ);
}
diff --git a/sys/dev/stg/tmc18c30_pccard.c b/sys/dev/stg/tmc18c30_pccard.c
index c1bf0e9..0cf518f 100644
--- a/sys/dev/stg/tmc18c30_pccard.c
+++ b/sys/dev/stg/tmc18c30_pccard.c
@@ -319,10 +319,13 @@ static void
stg_card_unload(DEVPORT_PDEVICE devi)
{
struct stg_softc *sc = DEVPORT_PDEVGET_SOFTC(devi);
+ intrmask_t s;
printf("%s: unload\n",sc->sc_sclow.sl_xname);
+ s = splcam();
scsi_low_deactivate((struct scsi_low_softc *)sc);
scsi_low_dettach(&sc->sc_sclow);
+ splx(s);
}
static int
@@ -353,7 +356,7 @@ stgattach(DEVPORT_PDEVICE devi)
struct scsi_low_softc *slp;
u_int32_t flags = DEVPORT_PDEVFLAGS(devi);
u_int iobase = DEVPORT_PDEVIOBASE(devi);
-
+ intrmask_t s;
char dvname[16];
strcpy(dvname,"stg");
@@ -393,9 +396,9 @@ stgattach(DEVPORT_PDEVICE devi)
slp->sl_hostid = STG_HOSTID;
slp->sl_cfgflags = flags;
+ s = splcam();
stgattachsubr(sc);
-
- sc->sc_ih = stgintr;
+ splx(s);
return(STGIOSZ);
}
diff --git a/sys/dev/stg/tmc18c30reg.h b/sys/dev/stg/tmc18c30reg.h
index 4a29f60..9c84d89 100644
--- a/sys/dev/stg/tmc18c30reg.h
+++ b/sys/dev/stg/tmc18c30reg.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $NecBSD: tmc18c30reg.h,v 1.4 1998/03/14 07:05:23 kmatsuda Exp $ */
+/* $NecBSD: tmc18c30reg.h,v 1.4.24.1 2001/06/08 06:27:50 honda Exp $ */
/* $NetBSD$ */
/*
@@ -57,14 +57,13 @@
#define BSTAT_REQ 0x10
#define BSTAT_SEL 0x20
#define BSTAT_ACK 0x40
-#define BSTAT_PHMASK (BSTAT_MSG | BSTAT_IO | BSTAT_CMD)
#define tmc_ictl 0x02
#define ICTL_FIFO 0x10
#define ICTL_ARBIT 0x20
#define ICTL_SEL 0x40
#define ICTL_CD 0x80
-#define ICTL_ALLINT (ICTL_ARBIT | ICTL_CD | ICTL_SEL)
+#define ICTL_ALLINT (ICTL_ARBIT | ICTL_CD | ICTL_SEL | ICTL_FIFO)
#define tmc_astat 0x02
#define ASTAT_INT 0x01
#define ASTAT_ARBIT 0x02
@@ -112,6 +111,7 @@
#define tmc_cfg1 0x0a
#define tmc_ioctl 0x0b
+#define IOCTL_IO32 0x80
#define tmc_cfg2 0x0b
#define tmc_wfifo 0x0c
@@ -127,11 +127,14 @@
#define STATUS_PHASE (BSTAT_CMD|BSTAT_BSY|BSTAT_IO)
#define MESSAGE_OUT_PHASE (BSTAT_CMD|BSTAT_MSG|BSTAT_BSY)
#define MESSAGE_IN_PHASE (BSTAT_CMD|BSTAT_MSG|BSTAT_BSY|BSTAT_IO)
-
#define PHASE_RESELECTED (BSTAT_SEL|BSTAT_IO)
-#define PHASE_MASK 0x2f
-#define RESEL_PHASE_MASK 0x2e
+#define BSTAT_PHMASK (BSTAT_MSG | BSTAT_IO | BSTAT_CMD)
+#define PHASE_MASK (BSTAT_SEL | BSTAT_BSY | BSTAT_PHMASK)
+#define RESEL_PHASE_MASK (BSTAT_SEL | BSTAT_PHMASK)
+
+#define STG_IS_PHASE_DATA(st) \
+ ((((st) & PHASE_MASK) & ~BSTAT_IO) == BSTAT_BSY)
/* chip type */
#define TMCCHIP_UNK 0x00
diff --git a/sys/dev/stg/tmc18c30var.h b/sys/dev/stg/tmc18c30var.h
index 0940fc7..ea713a0 100644
--- a/sys/dev/stg/tmc18c30var.h
+++ b/sys/dev/stg/tmc18c30var.h
@@ -1,12 +1,12 @@
/* $FreeBSD$ */
-/* $NecBSD: tmc18c30var.h,v 1.12 1998/11/30 00:08:30 honda Exp $ */
+/* $NecBSD: tmc18c30var.h,v 1.12.18.2 2001/06/13 05:51:23 honda Exp $ */
/* $NetBSD$ */
/*
* [NetBSD for NEC PC-98 series]
- * Copyright (c) 1996, 1997, 1998
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
* NetBSD/pc98 porting staff. All rights reserved.
- * Copyright (c) 1996, 1997, 1998
+ * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
* Naofumi HONDA. All rights reserved.
* Copyright (c) 1996, 1997, 1998
* Kouichi Matsuda. All rights reserved.
@@ -44,45 +44,57 @@
struct stg_softc {
struct scsi_low_softc sc_sclow; /* generic data */
+#ifdef __NetBSD__
bus_space_tag_t sc_iot;
bus_space_tag_t sc_memt;
bus_space_handle_t sc_ioh;
void *sc_ih;
+#endif /* __NetBSD__ */
- int sc_wc; /* weight counter */
+#ifdef __FreeBSD__
+ bus_space_tag_t sc_iot;
+ bus_space_tag_t sc_memt;
+ bus_space_handle_t sc_ioh;
+#if __FreeBSD_version >= 400001
+ int port_rid;
+ int irq_rid;
+ int mem_rid;
+ struct resource *port_res;
+ struct resource *irq_res;
+ struct resource *mem_res;
+
+ void *stg_intrhand;
+#endif /* __FreeBSD_version */
+#endif /* __FreeBSD__ */
+
+ int sc_tmaxcnt;
u_int sc_chip; /* chip type */
u_int sc_fsz; /* fifo size */
u_int sc_idbit; /* host id bit */
- u_int8_t sc_fcb; /* fifo intr thread */
+ u_int sc_wthold; /* write thread */
+ u_int sc_rthold; /* read thread */
+ u_int sc_maxwsize; /* max write size */
+ int sc_dataout_timeout; /* data out timeout counter */
+ int sc_ubf_timeout; /* unexpected bus free timeout */
u_int8_t sc_fcWinit; /* write flags */
u_int8_t sc_fcRinit; /* read flags */
- u_int8_t sc_fcsp; /* special control flags */
u_int8_t sc_icinit; /* interrupt masks */
u_int8_t sc_busc; /* default bus control register */
u_int8_t sc_imsg; /* identify msg required */
u_int8_t sc_busimg; /* bus control register image */
-#if defined (__FreeBSD__) && __FreeBSD_version >= 400001
- int port_rid;
- int irq_rid;
- int mem_rid;
- struct resource *port_res;
- struct resource *irq_res;
- struct resource *mem_res;
- void *stg_intrhand;
-#endif
};
/*****************************************************************
- * Target information
+ * Lun information
*****************************************************************/
struct stg_targ_info {
- struct targ_info sti_ti; /* generic data */
+ struct targ_info sti_ti; /* generic data */
- u_int8_t sti_reg_synch; /* synch register per target */
+ u_int8_t sti_reg_synch; /* synch register per lun */
};
/*****************************************************************
OpenPOWER on IntegriCloud