diff options
author | non <non@FreeBSD.org> | 2001-07-14 00:38:51 +0000 |
---|---|---|
committer | non <non@FreeBSD.org> | 2001-07-14 00:38:51 +0000 |
commit | e91272502526170cc4f62c2357a8b7d3ee9b2c27 (patch) | |
tree | 01f4c48045db66f0e363a543a36a88e13470d6c9 /sys/dev/stg | |
parent | a67c5263965b3cce0db11089854bd6f3f56f2f8e (diff) | |
download | FreeBSD-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.c | 995 | ||||
-rw-r--r-- | sys/dev/stg/tmc18c30_isa.c | 9 | ||||
-rw-r--r-- | sys/dev/stg/tmc18c30_pccard.c | 9 | ||||
-rw-r--r-- | sys/dev/stg/tmc18c30reg.h | 15 | ||||
-rw-r--r-- | sys/dev/stg/tmc18c30var.h | 48 |
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 */ }; /***************************************************************** |