tmc18c30.c revision 131920
179697Snon/*	$NecBSD: tmc18c30.c,v 1.28.12.3 2001/06/19 04:35:48 honda Exp $	*/
267468Snon/*	$NetBSD$	*/
367468Snon
467468Snon#define	STG_DEBUG
567468Snon#define	STG_STATICS
679697Snon#define	STG_IO_CONTROL_FLAGS	(STG_FIFO_INTERRUPTS | STG_WAIT_FOR_SELECT)
767468Snon
867468Snon/*
967468Snon * [NetBSD for NEC PC-98 series]
1079697Snon *  Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
1167468Snon *	NetBSD/pc98 porting staff. All rights reserved.
1279697Snon *  Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001
1367468Snon *	Naofumi HONDA. All rights reserved.
1467468Snon *  Copyright (c) 1996, 1997, 1998, 1999
1567468Snon *	Kouichi Matsuda. All rights reserved.
1667468Snon *
1767468Snon *  Redistribution and use in source and binary forms, with or without
1867468Snon *  modification, are permitted provided that the following conditions
1967468Snon *  are met:
2067468Snon *  1. Redistributions of source code must retain the above copyright
2167468Snon *     notice, this list of conditions and the following disclaimer.
2267468Snon *  2. Redistributions in binary form must reproduce the above copyright
2367468Snon *     notice, this list of conditions and the following disclaimer in the
2467468Snon *     documentation and/or other materials provided with the distribution.
2567468Snon *  3. The name of the author may not be used to endorse or promote products
2667468Snon *     derived from this software without specific prior written permission.
2767468Snon *
2867468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2967468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3067468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3167468Snon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
3267468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3367468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3467468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3567468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3667468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3767468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3867468Snon * POSSIBILITY OF SUCH DAMAGE.
3967468Snon */
40119420Sobrien
41119420Sobrien#include <sys/cdefs.h>
42119420Sobrien__FBSDID("$FreeBSD: head/sys/dev/stg/tmc18c30.c 131920 2004-07-10 21:14:20Z marcel $");
4367468Snon
4467468Snon#include <sys/param.h>
4567468Snon#include <sys/systm.h>
4667468Snon#include <sys/kernel.h>
4767468Snon#if defined(__FreeBSD__) && __FreeBSD_version >= 500001
4867468Snon#include <sys/bio.h>
4979697Snon#endif	/* __FreeBSD__ */
5067468Snon#include <sys/buf.h>
5167468Snon#include <sys/queue.h>
5267468Snon#include <sys/malloc.h>
5367468Snon#include <sys/errno.h>
5467468Snon
5567468Snon#ifdef __NetBSD__
5679697Snon#include <sys/device.h>
5767468Snon#include <machine/bus.h>
5867468Snon#include <machine/intr.h>
5967468Snon
6067468Snon#include <dev/scsipi/scsi_all.h>
6167468Snon#include <dev/scsipi/scsipi_all.h>
6267468Snon#include <dev/scsipi/scsiconf.h>
6367468Snon#include <dev/scsipi/scsi_disk.h>
6467468Snon
6567468Snon#include <machine/dvcfg.h>
6667468Snon#include <machine/physio_proc.h>
6767468Snon
6867468Snon#include <i386/Cbus/dev/scsi_low.h>
6967468Snon#include <i386/Cbus/dev/tmc18c30reg.h>
7067468Snon#include <i386/Cbus/dev/tmc18c30var.h>
7167468Snon#endif /* __NetBSD__ */
7267468Snon
7367468Snon#ifdef __FreeBSD__
7467468Snon#include <machine/clock.h>
7567468Snon#include <machine/cpu.h>
7667468Snon#include <machine/bus_pio.h>
7767468Snon#include <machine/bus.h>
7867468Snon
79126928Speter#include <compat/netbsd/dvcfg.h>
80126928Speter#include <compat/netbsd/physio_proc.h>
8167468Snon
8267468Snon#include <cam/scsi/scsi_low.h>
8367468Snon#include <dev/stg/tmc18c30reg.h>
8467468Snon#include <dev/stg/tmc18c30var.h>
8567468Snon#endif /* __FreeBSD__ */
8667468Snon
8767468Snon/***************************************************
8867468Snon * USER SETTINGS
8967468Snon ***************************************************/
9067468Snon/* DEVICE CONFIGURATION FLAGS (MINOR)
9167468Snon *
9267468Snon * 0x01   DISCONECT OFF
9367468Snon * 0x02   PARITY LINE OFF
9467468Snon * 0x04   IDENTIFY MSG OFF ( = single lun)
9567468Snon * 0x08   SYNC TRANSFER OFF
9667468Snon */
9767468Snon/* #define	STG_SYNC_SUPPORT */	/* NOT YET but easy */
9867468Snon
9967468Snon/* For the 512 fifo type: change below */
10067468Snon#define	TMC18C30_FIFOSZ	0x800
10179697Snon#define	TMC18C30_FCBSZ	0x200
10267468Snon#define	TMC18C50_FIFOSZ	0x2000
10379697Snon#define	TMC18C50_FCBSZ	0x400
10467468Snon
10579697Snon#define	STG_MAX_DATA_SIZE	(64 * 1024)
10679697Snon#define	STG_DELAY_MAX			(2 * 1000 * 1000)
10779697Snon#define	STG_DELAY_INTERVAL		(1)
10879697Snon#define	STG_DELAY_SELECT_POLLING_MAX	(5 * 1000 * 1000)
10979697Snon
11067468Snon/***************************************************
11167468Snon * PARAMS
11267468Snon ***************************************************/
11367468Snon#define	STG_NTARGETS	8
11467468Snon#define	STG_NLUNS	8
11567468Snon
11667468Snon/***************************************************
11767468Snon * DEBUG
11867468Snon ***************************************************/
11967468Snon#ifdef	STG_DEBUG
12089093Smsmithstatic int stg_debug;
12167468Snon#endif	/* STG_DEBUG */
12267468Snon
12367468Snon#ifdef	STG_STATICS
12489093Smsmithstatic struct stg_statics {
12579697Snon	int arbit_fail_0;
12679697Snon	int arbit_fail_1;
12767468Snon	int disconnect;
12867468Snon	int reselect;
12979697Snon} stg_statics;
13067468Snon#endif	/* STG_STATICS */
13167468Snon
13267468Snon/***************************************************
13379697Snon * IO control flags
13467468Snon ***************************************************/
13579697Snon#define	STG_FIFO_INTERRUPTS	0x0001
13679697Snon#define	STG_WAIT_FOR_SELECT	0x0100
13779697Snon
13879697Snonint stg_io_control = STG_IO_CONTROL_FLAGS;
13979697Snon
14079697Snon/***************************************************
14179697Snon * DEVICE STRUCTURE
14279697Snon ***************************************************/
14367468Snonextern struct cfdriver stg_cd;
14467468Snon
14567468Snon/**************************************************************
14667468Snon * DECLARE
14767468Snon **************************************************************/
14867468Snon/* static */
14992739Salfredstatic void stg_pio_read(struct stg_softc *, struct targ_info *, u_int);
15092739Salfredstatic void stg_pio_write(struct stg_softc *, struct targ_info *, u_int);
15192739Salfredstatic int stg_xfer(struct stg_softc *, u_int8_t *, int, int, int);
15292739Salfredstatic int stg_msg(struct stg_softc *, struct targ_info *, u_int);
15392739Salfredstatic int stg_reselected(struct stg_softc *);
15492739Salfredstatic int stg_disconnected(struct stg_softc *, struct targ_info *);
15592739Salfredstatic __inline void stg_pdma_end(struct stg_softc *, struct targ_info *);
15692739Salfredstatic int stghw_select_targ_wait(struct stg_softc *, int);
15792739Salfredstatic int stghw_check(struct stg_softc *);
15892739Salfredstatic void stghw_init(struct stg_softc *);
15992739Salfredstatic int stg_negate_signal(struct stg_softc *, u_int8_t, u_char *);
16092739Salfredstatic int stg_expect_signal(struct stg_softc *, u_int8_t, u_int8_t);
16192739Salfredstatic int stg_world_start(struct stg_softc *, int);
16292739Salfredstatic int stghw_start_selection(struct stg_softc *sc, struct slccb *);
16392739Salfredstatic void stghw_bus_reset(struct stg_softc *);
16492739Salfredstatic void stghw_attention(struct stg_softc *);
16592739Salfredstatic int stg_target_nexus_establish(struct stg_softc *);
16692739Salfredstatic int stg_lun_nexus_establish(struct stg_softc *);
16792739Salfredstatic int stg_ccb_nexus_establish(struct stg_softc *);
16892739Salfredstatic int stg_targ_init(struct stg_softc *, struct targ_info *, int);
16992739Salfredstatic __inline void stghw_bcr_write_1(struct stg_softc *, u_int8_t);
17092739Salfredstatic int stg_timeout(struct stg_softc *);
17192739Salfredstatic void stg_selection_done_and_expect_msgout(struct stg_softc *);
17267468Snon
17367468Snonstruct scsi_low_funcs stgfuncs = {
17467468Snon	SC_LOW_INIT_T stg_world_start,
17567468Snon	SC_LOW_BUSRST_T stghw_bus_reset,
17673025Snon	SC_LOW_TARG_INIT_T stg_targ_init,
17779697Snon	SC_LOW_LUN_INIT_T NULL,
17867468Snon
17967468Snon	SC_LOW_SELECT_T stghw_start_selection,
18079697Snon	SC_LOW_NEXUS_T stg_lun_nexus_establish,
18179697Snon	SC_LOW_NEXUS_T stg_ccb_nexus_establish,
18267468Snon
18367468Snon	SC_LOW_ATTEN_T stghw_attention,
18467468Snon	SC_LOW_MSG_T stg_msg,
18567468Snon
18679697Snon	SC_LOW_TIMEOUT_T stg_timeout,
18767468Snon	SC_LOW_POLL_T stgintr,
18867468Snon
18967468Snon	NULL,
19067468Snon};
19167468Snon
19267468Snon/****************************************************
19379697Snon * hwfuncs
19467468Snon ****************************************************/
19567468Snonstatic __inline void
19667468Snonstghw_bcr_write_1(sc, bcv)
19767468Snon	struct stg_softc *sc;
19867468Snon	u_int8_t bcv;
19967468Snon{
20067468Snon
20167468Snon	bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, bcv);
20267468Snon	sc->sc_busimg = bcv;
20367468Snon}
20467468Snon
20579697Snonstatic int
20679697Snonstghw_check(sc)
20779697Snon	struct stg_softc *sc;
20879697Snon{
20979697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
21079697Snon	bus_space_tag_t iot = sc->sc_iot;
21179697Snon	bus_space_handle_t ioh = sc->sc_ioh;
21279697Snon	u_int fcbsize, fcb;
21379697Snon	u_int16_t lsb, msb;
21479697Snon
21579697Snon	lsb = bus_space_read_1(iot, ioh, tmc_idlsb);
21679697Snon	msb = bus_space_read_1(iot, ioh, tmc_idmsb);
21779697Snon	switch (msb << 8 | lsb)
21879697Snon	{
21979697Snon		case 0x6127:
22079697Snon			/* TMCCHIP_1800 not supported. (it's my policy) */
22179697Snon			sc->sc_chip = TMCCHIP_1800;
22279697Snon			return EINVAL;
22379697Snon
22479697Snon		case 0x60e9:
22579697Snon			if (bus_space_read_1(iot, ioh, tmc_cfg2) & 0x02)
22679697Snon			{
22779697Snon				sc->sc_chip = TMCCHIP_18C30;
22879697Snon				sc->sc_fsz = TMC18C30_FIFOSZ;
22979697Snon				fcbsize = TMC18C30_FCBSZ;
23079697Snon			}
23179697Snon			else
23279697Snon			{
23379697Snon				sc->sc_chip = TMCCHIP_18C50;
23479697Snon				sc->sc_fsz = TMC18C50_FIFOSZ;
23579697Snon				fcbsize = TMC18C50_FCBSZ;
23679697Snon			}
23779697Snon			break;
23879697Snon
23979697Snon		default:
24079697Snon			sc->sc_chip = TMCCHIP_UNK;
24179697Snon			return ENODEV;
24279697Snon	}
24379697Snon
24479697Snon	sc->sc_fcRinit = FCTL_INTEN;
24579697Snon	sc->sc_fcWinit = FCTL_PARENB | FCTL_INTEN;
24679697Snon
24779697Snon	if (slp->sl_cfgflags & CFG_NOATTEN)
24879697Snon		sc->sc_imsg = 0;
24979697Snon	else
25079697Snon		sc->sc_imsg = BCTL_ATN;
25179697Snon	sc->sc_busc = BCTL_BUSEN;
25279697Snon
25379697Snon	sc->sc_wthold = fcbsize + 256;
25479697Snon	sc->sc_rthold = fcbsize - 256;
25579697Snon	sc->sc_maxwsize = sc->sc_fsz;
25679697Snon
25779697Snon	fcb = fcbsize / (sc->sc_fsz / 16);
25879697Snon	sc->sc_icinit = ICTL_CD | ICTL_SEL | ICTL_ARBIT | fcb;
25979697Snon	return 0;
26079697Snon}
26179697Snon
26267468Snonstatic void
26379697Snonstghw_init(sc)
26479697Snon	struct stg_softc *sc;
26579697Snon{
26679697Snon	bus_space_tag_t iot = sc->sc_iot;
26779697Snon	bus_space_handle_t ioh = sc->sc_ioh;
26879697Snon
26979697Snon	bus_space_write_1(iot, ioh, tmc_ictl, 0);
27079697Snon	stghw_bcr_write_1(sc, BCTL_BUSFREE);
27179697Snon	bus_space_write_1(iot, ioh, tmc_fctl,
27279697Snon			  sc->sc_fcRinit | FCTL_CLRFIFO | FCTL_CLRINT);
27379697Snon	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
27479697Snon	bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
27579697Snon
27679697Snon	bus_space_write_1(iot, ioh, tmc_ssctl, 0);
27779697Snon}
27879697Snon
27979697Snonstatic int
28079697Snonstg_targ_init(sc, ti, action)
28179697Snon	struct stg_softc *sc;
28279697Snon	struct targ_info *ti;
28379697Snon	int action;
28479697Snon{
28579697Snon	struct stg_targ_info *sti = (void *) ti;
28679697Snon
28779697Snon	if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
28879697Snon	{
28979697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
29079697Snon		ti->ti_maxsynch.period = 0;
29179697Snon		ti->ti_maxsynch.offset = 0;
29279697Snon		sti->sti_reg_synch = 0;
29379697Snon	}
29479697Snon	return 0;
29579697Snon}
29679697Snon
29779697Snon/****************************************************
29879697Snon * scsi low interface
29979697Snon ****************************************************/
30079697Snonstatic void
30167468Snonstghw_attention(sc)
30267468Snon	struct stg_softc *sc;
30367468Snon{
30467468Snon
30567468Snon	sc->sc_busc |= BCTL_ATN;
30667468Snon	sc->sc_busimg |= BCTL_ATN;
30767468Snon	bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, sc->sc_busimg);
30879697Snon	SCSI_LOW_DELAY(10);
30967468Snon}
31067468Snon
31167468Snonstatic void
31267468Snonstghw_bus_reset(sc)
31367468Snon	struct stg_softc *sc;
31467468Snon{
31567468Snon	bus_space_tag_t iot = sc->sc_iot;
31667468Snon	bus_space_handle_t ioh = sc->sc_ioh;
31767468Snon
31867468Snon	bus_space_write_1(iot, ioh, tmc_ictl, 0);
31967468Snon	bus_space_write_1(iot, ioh, tmc_fctl, 0);
32067468Snon	stghw_bcr_write_1(sc, BCTL_RST);
32179697Snon	SCSI_LOW_DELAY(100000);
32267468Snon	stghw_bcr_write_1(sc, BCTL_BUSFREE);
32367468Snon}
32467468Snon
32567468Snonstatic int
32667468Snonstghw_start_selection(sc, cb)
32767468Snon	struct stg_softc *sc;
32867468Snon	struct slccb *cb;
32967468Snon{
33067468Snon	bus_space_tag_t iot = sc->sc_iot;
33167468Snon	bus_space_handle_t ioh = sc->sc_ioh;
33267468Snon	struct targ_info *ti = cb->ti;
33367468Snon	register u_int8_t stat;
33467468Snon	int s;
33567468Snon
33679697Snon	sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
33779697Snon	sc->sc_dataout_timeout = 0;
33879697Snon	sc->sc_ubf_timeout = 0;
33967468Snon	stghw_bcr_write_1(sc, BCTL_BUSFREE);
34079697Snon	bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
34167468Snon
34267468Snon	s = splhigh();
34379697Snon	stat = bus_space_read_1(iot, ioh, tmc_astat);
34479697Snon	if ((stat & ASTAT_INT) != 0)
34567468Snon	{
34679697Snon		splx(s);
34779697Snon		return SCSI_LOW_START_FAIL;
34867468Snon	}
34967468Snon
35067468Snon	bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit);
35167468Snon	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_ARBIT);
35267468Snon	splx(s);
35367468Snon
35467468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART);
35567468Snon	return SCSI_LOW_START_OK;
35667468Snon}
35767468Snon
35867468Snonstatic int
35967468Snonstg_world_start(sc, fdone)
36067468Snon	struct stg_softc *sc;
36167468Snon	int fdone;
36267468Snon{
36367468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
36467468Snon	int error;
36567468Snon
36679697Snon	if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
36779697Snon		sc->sc_fcRinit |= FCTL_PARENB;
36879697Snon	else
36979697Snon		sc->sc_fcRinit &= ~FCTL_PARENB;
37079697Snon
37167468Snon	if ((error = stghw_check(sc)) != 0)
37267468Snon		return error;
37367468Snon
37467468Snon	stghw_init(sc);
37567468Snon	scsi_low_bus_reset(slp);
37667468Snon	stghw_init(sc);
37767468Snon
37867468Snon	SOFT_INTR_REQUIRED(slp);
37967468Snon	return 0;
38067468Snon}
38167468Snon
38267468Snonstatic int
38367468Snonstg_msg(sc, ti, msg)
38467468Snon	struct stg_softc *sc;
38567468Snon	struct targ_info *ti;
38667468Snon	u_int msg;
38767468Snon{
38879697Snon	bus_space_tag_t iot = sc->sc_iot;
38979697Snon	bus_space_handle_t ioh = sc->sc_ioh;
39073025Snon	struct stg_targ_info *sti = (void *) ti;
39167468Snon	u_int period, offset;
39267468Snon
39379697Snon	if ((msg & SCSI_LOW_MSG_WIDE) != 0)
39479697Snon	{
39579697Snon		if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
39679697Snon		{
39779697Snon			ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
39879697Snon			return EINVAL;
39979697Snon		}
40079697Snon		return 0;
40179697Snon	}
40267468Snon
40379697Snon	if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
40479697Snon		return 0;
40579697Snon
40673025Snon 	period = ti->ti_maxsynch.period;
40773025Snon	offset = ti->ti_maxsynch.offset;
40867468Snon	period = period << 2;
40967468Snon	if (period >= 200)
41067468Snon	{
41173025Snon		sti->sti_reg_synch = (period - 200) / 50;
41267468Snon		if (period % 50)
41373025Snon			sti->sti_reg_synch ++;
41473025Snon		sti->sti_reg_synch |= SSCTL_SYNCHEN;
41567468Snon	}
41667468Snon	else if (period >= 100)
41767468Snon	{
41873025Snon		sti->sti_reg_synch = (period - 100) / 50;
41967468Snon		if (period % 50)
42073025Snon			sti->sti_reg_synch ++;
42173025Snon		sti->sti_reg_synch |= SSCTL_SYNCHEN | SSCTL_FSYNCHEN;
42267468Snon	}
42379697Snon	bus_space_write_1(iot, ioh, tmc_ssctl, sti->sti_reg_synch);
42467468Snon	return 0;
42567468Snon}
42667468Snon
42767468Snon/**************************************************************
42867468Snon * General probe attach
42967468Snon **************************************************************/
43067468Snonint
43167468Snonstgprobesubr(iot, ioh, dvcfg)
43267468Snon	bus_space_tag_t iot;
43367468Snon	bus_space_handle_t ioh;
43467468Snon	u_int dvcfg;
43567468Snon{
43667468Snon	u_int16_t lsb, msb;
43767468Snon
43867468Snon	lsb = bus_space_read_1(iot, ioh, tmc_idlsb);
43967468Snon	msb = bus_space_read_1(iot, ioh, tmc_idmsb);
44067468Snon	switch (msb << 8 | lsb)
44167468Snon	{
44267468Snon		default:
44367468Snon			return 0;
44467468Snon		case 0x6127:
44567468Snon			/* not support! */
44667468Snon			return 0;
44767468Snon		case 0x60e9:
44867468Snon			return 1;
44967468Snon	}
45067468Snon	return 0;
45167468Snon}
45267468Snon
45367468Snonint
45467468Snonstgprint(aux, name)
45567468Snon	void *aux;
45667468Snon	const char *name;
45767468Snon{
45867468Snon
45967468Snon	if (name != NULL)
46067468Snon		printf("%s: scsibus ", name);
46167468Snon	return UNCONF;
46267468Snon}
46367468Snon
46467468Snonvoid
46567468Snonstgattachsubr(sc)
46667468Snon	struct stg_softc *sc;
46767468Snon{
46867468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
46967468Snon
47067468Snon	printf("\n");
47167468Snon
47267468Snon	sc->sc_idbit = (1 << slp->sl_hostid);
47367468Snon	slp->sl_funcs = &stgfuncs;
47479697Snon	sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
47567468Snon
47679697Snon	slp->sl_flags |= HW_READ_PADDING;
47767468Snon	slp->sl_cfgflags |= CFG_ASYNC;	/* XXX */
47867468Snon
47979697Snon	(void) scsi_low_attach(slp, 0, STG_NTARGETS, STG_NLUNS,
48079697Snon				sizeof(struct stg_targ_info), 0);
48167468Snon}
48267468Snon
48367468Snon/**************************************************************
48467468Snon * PDMA functions
48567468Snon **************************************************************/
48667468Snonstatic __inline void
48767468Snonstg_pdma_end(sc, ti)
48867468Snon	struct stg_softc *sc;
48967468Snon	struct targ_info *ti;
49067468Snon{
49167468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
49267468Snon	bus_space_tag_t iot = sc->sc_iot;
49367468Snon	bus_space_handle_t ioh = sc->sc_ioh;
49479697Snon	struct slccb *cb = slp->sl_Qnexus;
49567468Snon	u_int len, tres;
49667468Snon
49767468Snon	slp->sl_flags &= ~HW_PDMASTART;
49879697Snon	sc->sc_icinit &= ~ICTL_FIFO;
49979697Snon	sc->sc_dataout_timeout = 0;
50067468Snon
50179697Snon	if (cb == NULL)
50279697Snon	{
50379697Snon		slp->sl_error |= PDMAERR;
50479697Snon		goto out;
50579697Snon	}
50679697Snon
50767468Snon	if (ti->ti_phase == PH_DATA)
50867468Snon	{
50967468Snon		len = bus_space_read_2(iot, ioh, tmc_fdcnt);
51067468Snon		if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
51167468Snon		{
51267468Snon			if (len != 0)
51367468Snon			{
51467468Snon				tres = len + slp->sl_scp.scp_datalen;
51567468Snon				if (tres <= (u_int) cb->ccb_scp.scp_datalen)
51667468Snon				{
51767468Snon					slp->sl_scp.scp_data -= len;
51867468Snon					slp->sl_scp.scp_datalen = tres;
51967468Snon				}
52067468Snon				else
52167468Snon				{
52267468Snon					slp->sl_error |= PDMAERR;
52367468Snon					printf("%s len %x >= datalen %x\n",
52467468Snon						slp->sl_xname,
52567468Snon						len, slp->sl_scp.scp_datalen);
52667468Snon				}
52767468Snon			}
52867468Snon		}
52967468Snon		else if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
53067468Snon		{
53167468Snon			if (len != 0)
53267468Snon			{
53367468Snon				slp->sl_error |= PDMAERR;
53467468Snon				printf("%s: len %x left in fifo\n",
53567468Snon					slp->sl_xname, len);
53667468Snon			}
53767468Snon		}
53879697Snon		scsi_low_data_finish(slp);
53967468Snon	}
54067468Snon	else
54167468Snon	{
54267468Snon
54367468Snon		printf("%s data phase miss\n", slp->sl_xname);
54467468Snon		slp->sl_error |= PDMAERR;
54567468Snon	}
54667468Snon
54779697Snonout:
54867468Snon	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
54967468Snon}
55067468Snon
55167468Snonstatic void
55279697Snonstg_pio_read(sc, ti, thold)
55367468Snon	struct stg_softc *sc;
55467468Snon	struct targ_info *ti;
55579697Snon	u_int thold;
55667468Snon{
55767468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
55867468Snon	bus_space_tag_t iot = sc->sc_iot;
55967468Snon	bus_space_handle_t ioh = sc->sc_ioh;
56067468Snon	struct sc_p *sp = &slp->sl_scp;
56179697Snon	int s, tout;
56267468Snon	u_int res;
56367468Snon	u_int8_t stat;
56467468Snon
56579697Snon	if ((slp->sl_flags & HW_PDMASTART) == 0)
56679697Snon	{
56779697Snon		bus_space_write_1(iot, ioh, tmc_fctl,
56879697Snon				  sc->sc_fcRinit | FCTL_FIFOEN);
56979697Snon		slp->sl_flags |= HW_PDMASTART;
57079697Snon	}
57167468Snon
57279697Snon	tout = sc->sc_tmaxcnt;
57379697Snon	while (tout -- > 0)
57467468Snon	{
57579697Snon		if (thold > 0)
57667468Snon		{
57779697Snon			s = splhigh();
57879697Snon			res = bus_space_read_2(iot, ioh, tmc_fdcnt);
57979697Snon			if (res < thold)
58079697Snon			{
58179697Snon				bus_space_write_1(iot, ioh, tmc_ictl,
58279697Snon						  sc->sc_icinit);
58379697Snon				splx(s);
58479697Snon				break;
58579697Snon			}
58679697Snon			splx(s);
58779697Snon		}
58879697Snon		else
58979697Snon		{
59067468Snon			stat = bus_space_read_1(iot, ioh, tmc_bstat);
59179697Snon			res = bus_space_read_2(iot, ioh, tmc_fdcnt);
59279697Snon			if (res == 0)
59379697Snon			{
59479697Snon				if ((stat & PHASE_MASK) != DATA_IN_PHASE)
59579697Snon					break;
59679697Snon				if (sp->scp_datalen <= 0)
59779697Snon					break;
59879697Snon				SCSI_LOW_DELAY(1);
59967468Snon				continue;
60079697Snon			}
60167468Snon		}
60267468Snon
60379697Snon		/* The assumtion res != 0 is valid here */
60467468Snon		if (res > sp->scp_datalen)
60567468Snon		{
60679697Snon			if (res == (u_int) -1)
60779697Snon				break;
60879697Snon
60967468Snon			slp->sl_error |= PDMAERR;
61079697Snon			if ((slp->sl_flags & HW_READ_PADDING) == 0)
61179697Snon			{
61279697Snon				printf("%s: read padding required\n",
61379697Snon					slp->sl_xname);
61479697Snon				break;
61579697Snon			}
61679697Snon
61779697Snon			sp->scp_datalen = 0;
61879697Snon			if (res > STG_MAX_DATA_SIZE)
61979697Snon				res = STG_MAX_DATA_SIZE;
62079697Snon			while (res -- > 0)
62179697Snon			{
62279697Snon				(void) bus_space_read_1(iot, ioh, tmc_rfifo);
62379697Snon			}
62479697Snon			continue;
62567468Snon		}
62667468Snon
62767468Snon		sp->scp_datalen -= res;
62867468Snon		if (res & 1)
62967468Snon		{
63067468Snon			*sp->scp_data = bus_space_read_1(iot, ioh, tmc_rfifo);
63167468Snon			sp->scp_data ++;
63267468Snon			res --;
63367468Snon		}
63467468Snon
63567468Snon		bus_space_read_multi_2(iot, ioh, tmc_rfifo,
63667468Snon				       (u_int16_t *) sp->scp_data, res >> 1);
63767468Snon		sp->scp_data += res;
63867468Snon	}
63967468Snon
64073025Snon	if (tout <= 0)
64179697Snon		printf("%s: pio read timeout\n", slp->sl_xname);
64267468Snon}
64367468Snon
64467468Snonstatic void
64579697Snonstg_pio_write(sc, ti, thold)
64667468Snon	struct stg_softc *sc;
64767468Snon	struct targ_info *ti;
64879697Snon	u_int thold;
64967468Snon{
65067468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
65167468Snon	bus_space_tag_t iot = sc->sc_iot;
65267468Snon	bus_space_handle_t ioh = sc->sc_ioh;
65367468Snon	struct sc_p *sp = &slp->sl_scp;
65467468Snon	u_int res;
65579697Snon	int s, tout;
65667468Snon	register u_int8_t stat;
65767468Snon
65879697Snon	if ((slp->sl_flags & HW_PDMASTART) == 0)
65979697Snon	{
66079697Snon		stat = sc->sc_fcWinit | FCTL_FIFOEN | FCTL_FIFOW;
66179697Snon		bus_space_write_1(iot, ioh, tmc_fctl, stat | FCTL_CLRFIFO);
66279697Snon		bus_space_write_1(iot, ioh, tmc_fctl, stat);
66379697Snon		slp->sl_flags |= HW_PDMASTART;
66479697Snon	}
66567468Snon
66679697Snon	tout = sc->sc_tmaxcnt;
66779697Snon	while (tout -- > 0)
66867468Snon	{
66967468Snon		stat = bus_space_read_1(iot, ioh, tmc_bstat);
67079697Snon		if ((stat & PHASE_MASK) != DATA_OUT_PHASE)
67167468Snon			break;
67267468Snon
67379697Snon		if (sp->scp_datalen <= 0)
67479697Snon		{
67579697Snon			if (sc->sc_dataout_timeout == 0)
67679697Snon				sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
67779697Snon			break;
67879697Snon		}
67967468Snon
68079697Snon		if (thold > 0)
68179697Snon		{
68279697Snon			s = splhigh();
68379697Snon			res = bus_space_read_2(iot, ioh, tmc_fdcnt);
68479697Snon			if (res > thold)
68579697Snon			{
68679697Snon				bus_space_write_1(iot, ioh, tmc_ictl,
68779697Snon						  sc->sc_icinit);
68879697Snon				splx(s);
68979697Snon				break;
69079697Snon			}
69179697Snon			splx(s);
69279697Snon		}
69379697Snon		else
69479697Snon		{
69579697Snon			res = bus_space_read_2(iot, ioh, tmc_fdcnt);
69679697Snon			if (res > sc->sc_maxwsize / 2)
69779697Snon			{
69879697Snon				SCSI_LOW_DELAY(1);
69979697Snon				continue;
70079697Snon			}
70179697Snon		}
70279697Snon
70379697Snon		if (res == (u_int) -1)
70479697Snon			break;
70579697Snon		res = sc->sc_maxwsize - res;
70679697Snon		if (res > sp->scp_datalen)
70779697Snon			res = sp->scp_datalen;
70879697Snon
70967468Snon		sp->scp_datalen -= res;
71067468Snon		if ((res & 0x1) != 0)
71167468Snon		{
71267468Snon			bus_space_write_1(iot, ioh, tmc_wfifo, *sp->scp_data);
71367468Snon			sp->scp_data ++;
71467468Snon			res --;
71567468Snon		}
71667468Snon
71767468Snon		bus_space_write_multi_2(iot, ioh, tmc_wfifo,
71867468Snon					(u_int16_t *) sp->scp_data, res >> 1);
71967468Snon		sp->scp_data += res;
72067468Snon	}
72167468Snon
72273025Snon	if (tout <= 0)
72379697Snon		printf("%s: pio write timeout\n", slp->sl_xname);
72467468Snon}
72567468Snon
72667468Snonstatic int
72767468Snonstg_negate_signal(sc, mask, s)
72867468Snon	struct stg_softc *sc;
72967468Snon	u_int8_t mask;
73067468Snon	u_char *s;
73167468Snon{
73267468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
73367468Snon	bus_space_tag_t bst = sc->sc_iot;
73467468Snon	bus_space_handle_t bsh = sc->sc_ioh;
73579697Snon	int wc;
73667468Snon	u_int8_t regv;
73767468Snon
73879697Snon	for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++)
73967468Snon	{
74067468Snon		regv = bus_space_read_1(bst, bsh, tmc_bstat);
74179697Snon		if (regv == (u_int8_t) -1)
74279697Snon			return -1;
74379697Snon		if ((regv & mask) == 0)
74479697Snon			return 1;
74579697Snon
74679697Snon		SCSI_LOW_DELAY(STG_DELAY_INTERVAL);
74767468Snon	}
74867468Snon
74979697Snon	printf("%s: %s stg_negate_signal timeout\n", slp->sl_xname, s);
75079697Snon	return -1;
75167468Snon}
75267468Snon
75367468Snonstatic int
75467468Snonstg_expect_signal(sc, phase, mask)
75567468Snon	struct stg_softc *sc;
75667468Snon	u_int8_t phase, mask;
75767468Snon{
75867468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
75967468Snon	bus_space_tag_t bst = sc->sc_iot;
76067468Snon	bus_space_handle_t bsh = sc->sc_ioh;
76179697Snon	int wc;
76267468Snon	u_int8_t ph;
76367468Snon
76479697Snon	phase &= PHASE_MASK;
76579697Snon	for (wc = 0; wc < STG_DELAY_MAX / STG_DELAY_INTERVAL; wc ++)
76667468Snon	{
76767468Snon		ph = bus_space_read_1(bst, bsh, tmc_bstat);
76879697Snon		if (ph == (u_int8_t) -1)
76979697Snon			return -1;
77079697Snon		if ((ph & PHASE_MASK) != phase)
77179697Snon			return 0;
77279697Snon		if ((ph & mask) != 0)
77379697Snon			return 1;
77479697Snon
77579697Snon		SCSI_LOW_DELAY(STG_DELAY_INTERVAL);
77667468Snon	}
77767468Snon
77879697Snon	printf("%s: stg_expect_signal timeout\n", slp->sl_xname);
77979697Snon	return -1;
78067468Snon}
78167468Snon
78267468Snonstatic int
78379697Snonstg_xfer(sc, buf, len, phase, clear_atn)
78467468Snon	struct stg_softc *sc;
78567468Snon	u_int8_t *buf;
78667468Snon	int len;
78767468Snon	int phase;
78879697Snon	int clear_atn;
78967468Snon{
79067468Snon	bus_space_tag_t iot = sc->sc_iot;
79167468Snon	bus_space_handle_t ioh = sc->sc_ioh;
79279697Snon	int rv, ptr;
79367468Snon
79467468Snon	if (phase & BSTAT_IO)
79567468Snon		bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
79667468Snon	else
79767468Snon		bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit);
79867468Snon
79967468Snon	for (ptr = 0; len > 0; len --)
80067468Snon	{
80167468Snon		rv = stg_expect_signal(sc, phase, BSTAT_REQ);
80267468Snon		if (rv <= 0)
80367468Snon			goto bad;
80467468Snon
80579697Snon		if (len == 1 && clear_atn != 0)
80667468Snon		{
80767468Snon			sc->sc_busc &= ~BCTL_ATN;
80867468Snon			stghw_bcr_write_1(sc, sc->sc_busc);
80979697Snon			SCSI_LOW_DEASSERT_ATN(&sc->sc_sclow);
81067468Snon		}
81167468Snon
81267468Snon		if (phase & BSTAT_IO)
81367468Snon		{
81467468Snon			buf[ptr ++] = bus_space_read_1(iot, ioh, tmc_rdata);
81567468Snon		}
81667468Snon		else
81767468Snon		{
81867468Snon			bus_space_write_1(iot, ioh, tmc_wdata, buf[ptr ++]);
81967468Snon		}
82079697Snon
82167468Snon		stg_negate_signal(sc, BSTAT_ACK, "xfer<ACK>");
82267468Snon	}
82367468Snon
82467468Snonbad:
82567468Snon	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
82667468Snon	return len;
82767468Snon}
82867468Snon
82967468Snon/**************************************************************
83067468Snon * disconnect & reselect (HW low)
83167468Snon **************************************************************/
83267468Snonstatic int
83367468Snonstg_reselected(sc)
83467468Snon	struct stg_softc *sc;
83567468Snon{
83667468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
83767468Snon	bus_space_tag_t iot = sc->sc_iot;
83867468Snon	bus_space_handle_t ioh = sc->sc_ioh;
83979697Snon	int tout;
84067468Snon	u_int sid;
84179697Snon	u_int8_t regv;
84267468Snon
84367468Snon	if (slp->sl_selid != NULL)
84467468Snon	{
84567468Snon		/* XXX:
84667468Snon		 * Selection vs Reselection conflicts.
84767468Snon		 */
84867468Snon		bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
84967468Snon		stghw_bcr_write_1(sc, BCTL_BUSFREE);
85067468Snon	}
85179697Snon	else if (slp->sl_Tnexus != NULL)
85279697Snon	{
85379697Snon		printf("%s: unexpected termination\n", slp->sl_xname);
85479697Snon		stg_disconnected(sc, slp->sl_Tnexus);
85579697Snon	}
85667468Snon
85767468Snon	/* XXX:
85867468Snon	 * We should ack the reselection as soon as possible,
859123608Sjhb	 * because the target would abort the current reselection seq
86067468Snon  	 * due to reselection timeout.
86167468Snon	 */
86279697Snon	tout = STG_DELAY_SELECT_POLLING_MAX;
86379697Snon	while (tout -- > 0)
86479697Snon	{
86579697Snon		regv = bus_space_read_1(iot, ioh, tmc_bstat);
86679697Snon		if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) ==
86779697Snon			    (BSTAT_IO | BSTAT_SEL))
86879697Snon		{
86979697Snon			SCSI_LOW_DELAY(1);
87079697Snon			regv = bus_space_read_1(iot, ioh, tmc_bstat);
87179697Snon			if ((regv & (BSTAT_IO | BSTAT_SEL | BSTAT_BSY)) ==
87279697Snon				    (BSTAT_IO | BSTAT_SEL))
87379697Snon				goto reselect_start;
87479697Snon		}
87579697Snon		SCSI_LOW_DELAY(1);
87679697Snon	}
87779697Snon	printf("%s: reselction timeout I\n", slp->sl_xname);
87879697Snon	return EJUSTRETURN;
87979697Snon
88079697Snonreselect_start:
88167468Snon	sid = (u_int) bus_space_read_1(iot, ioh, tmc_scsiid);
88279697Snon	if ((sid & sc->sc_idbit) == 0)
88379697Snon	{
88479697Snon		/* not us */
88579697Snon		return EJUSTRETURN;
88679697Snon	}
88779697Snon
88879697Snon	bus_space_write_1(iot, ioh, tmc_fctl,
88979697Snon			    sc->sc_fcRinit | FCTL_CLRFIFO | FCTL_CLRINT);
89067468Snon	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
89167468Snon	stghw_bcr_write_1(sc, sc->sc_busc | BCTL_BSY);
89267468Snon
89379697Snon	while (tout -- > 0)
89479697Snon	{
89579697Snon		regv = bus_space_read_1(iot, ioh, tmc_bstat);
89679697Snon		if ((regv & (BSTAT_SEL | BSTAT_BSY)) == BSTAT_BSY)
89779697Snon			goto reselected;
89879697Snon		SCSI_LOW_DELAY(1);
89979697Snon	}
90079697Snon	printf("%s: reselction timeout II\n", slp->sl_xname);
90179697Snon	return EJUSTRETURN;
90279697Snon
90379697Snonreselected:
90467468Snon	sid &= ~sc->sc_idbit;
90567468Snon	sid = ffs(sid) - 1;
90679697Snon	if (scsi_low_reselected(slp, sid) == NULL)
90767468Snon		return EJUSTRETURN;
90867468Snon
90967468Snon#ifdef	STG_STATICS
91079697Snon	stg_statics.reselect ++;
91167468Snon#endif	/* STG_STATICS */
91267468Snon	return EJUSTRETURN;
91367468Snon}
91467468Snon
91579697Snonstatic int
91667468Snonstg_disconnected(sc, ti)
91767468Snon	struct stg_softc *sc;
91867468Snon	struct targ_info *ti;
91967468Snon{
92067468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
92167468Snon	bus_space_tag_t iot = sc->sc_iot;
92267468Snon	bus_space_handle_t ioh = sc->sc_ioh;
92367468Snon
92467468Snon	/* clear bus status & fifo */
92567468Snon	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO);
92667468Snon	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
92767468Snon	stghw_bcr_write_1(sc, BCTL_BUSFREE);
92879697Snon	sc->sc_icinit &= ~ICTL_FIFO;
92967468Snon	sc->sc_busc &= ~BCTL_ATN;
93079697Snon	sc->sc_dataout_timeout = 0;
93179697Snon	sc->sc_ubf_timeout = 0;
93267468Snon
93367468Snon#ifdef	STG_STATICS
93479697Snon	stg_statics.disconnect ++;
93567468Snon#endif	/* STG_STATICS */
93667468Snon	scsi_low_disconnected(slp, ti);
93767468Snon	return 1;
93867468Snon}
93967468Snon
94067468Snon/**************************************************************
94167468Snon * SEQUENCER
94267468Snon **************************************************************/
94367468Snonstatic int
94479697Snonstg_target_nexus_establish(sc)
94567468Snon	struct stg_softc *sc;
94667468Snon{
94779697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
94867468Snon	bus_space_tag_t iot = sc->sc_iot;
94967468Snon	bus_space_handle_t ioh = sc->sc_ioh;
95079697Snon	struct targ_info *ti = slp->sl_Tnexus;
95173025Snon	struct stg_targ_info *sti = (void *) ti;
95267468Snon
95373025Snon	bus_space_write_1(iot, ioh, tmc_ssctl, sti->sti_reg_synch);
95479697Snon	if ((stg_io_control & STG_FIFO_INTERRUPTS) != 0)
95579697Snon	{
95679697Snon		sc->sc_icinit |= ICTL_FIFO;
95779697Snon	}
95867468Snon	return 0;
95967468Snon}
96067468Snon
96167468Snonstatic int
96279697Snonstg_lun_nexus_establish(sc)
96367468Snon	struct stg_softc *sc;
96467468Snon{
96579697Snon
96679697Snon	return 0;
96779697Snon}
96879697Snon
96979697Snonstatic int
97079697Snonstg_ccb_nexus_establish(sc)
97179697Snon	struct stg_softc *sc;
97279697Snon{
97379697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
97479697Snon	struct slccb *cb = slp->sl_Qnexus;
97579697Snon
97679697Snon	sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
97779697Snon	return 0;
97879697Snon}
97979697Snon
98079697Snon#define	STGHW_SELECT_INTERVAL	10
98179697Snon
98279697Snonstatic int
98379697Snonstghw_select_targ_wait(sc, mu)
98479697Snon	struct stg_softc *sc;
98579697Snon	int mu;
98679697Snon{
98767468Snon	bus_space_tag_t iot = sc->sc_iot;
98867468Snon	bus_space_handle_t ioh = sc->sc_ioh;
98967468Snon
99079697Snon	mu = mu / STGHW_SELECT_INTERVAL;
99179697Snon	while (mu -- > 0)
99267468Snon	{
99379697Snon		if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) == 0)
99467468Snon		{
99579697Snon			SCSI_LOW_DELAY(STGHW_SELECT_INTERVAL);
99679697Snon			continue;
99767468Snon		}
99879697Snon		SCSI_LOW_DELAY(1);
99979697Snon		if ((bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) != 0)
100079697Snon		{
100179697Snon			return 0;
100279697Snon		}
100367468Snon	}
100479697Snon	return ENXIO;
100579697Snon}
100667468Snon
100779697Snonstatic void
100879697Snonstg_selection_done_and_expect_msgout(sc)
100979697Snon	struct stg_softc *sc;
101079697Snon{
101179697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
101279697Snon	bus_space_tag_t iot = sc->sc_iot;
101379697Snon	bus_space_handle_t ioh = sc->sc_ioh;
101479697Snon
101567468Snon	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO);
101667468Snon	bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
101779697Snon	stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc);
101879697Snon	SCSI_LOW_ASSERT_ATN(slp);
101967468Snon}
102067468Snon
102167468Snonint
102267468Snonstgintr(arg)
102367468Snon	void *arg;
102467468Snon{
102567468Snon	struct stg_softc *sc = arg;
102667468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
102767468Snon	bus_space_tag_t iot = sc->sc_iot;
102867468Snon	bus_space_handle_t ioh = sc->sc_ioh;
102967468Snon	struct targ_info *ti;
103067468Snon	struct physio_proc *pp;
103167468Snon	struct buf *bp;
103279697Snon	u_int derror, flags;
103379697Snon	int len, s;
103467468Snon	u_int8_t status, astatus, regv;
103567468Snon
103667468Snon	/*******************************************
103767468Snon	 * interrupt check
103867468Snon	 *******************************************/
103967468Snon	if (slp->sl_flags & HW_INACTIVE)
104067468Snon		return 0;
104167468Snon
104267468Snon	astatus = bus_space_read_1(iot, ioh, tmc_astat);
104367468Snon	status = bus_space_read_1(iot, ioh, tmc_bstat);
104467468Snon
104579697Snon	if ((astatus & ASTAT_STATMASK) == 0 || astatus == (u_int8_t) -1)
104667468Snon		return 0;
104767468Snon
104879697Snon	bus_space_write_1(iot, ioh, tmc_ictl, 0);
104967468Snon	if (astatus & ASTAT_SCSIRST)
105067468Snon	{
105167468Snon		bus_space_write_1(iot, ioh, tmc_fctl,
105267468Snon				  sc->sc_fcRinit | FCTL_CLRFIFO);
105367468Snon		bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
105479697Snon		bus_space_write_1(iot, ioh, tmc_ictl, 0);
105567468Snon
105667468Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT,
105767468Snon				 "bus reset (power off?)");
105867468Snon		return 1;
105967468Snon	}
106067468Snon
106167468Snon	/*******************************************
106267468Snon	 * debug section
106367468Snon	 *******************************************/
106467468Snon#ifdef	STG_DEBUG
106567468Snon	if (stg_debug)
106667468Snon	{
106767468Snon		scsi_low_print(slp, NULL);
106879697Snon		printf("%s: st %x ist %x\n\n", slp->sl_xname,
106967468Snon		       status, astatus);
1070131920Smarcel#ifdef	KDB
107167468Snon		if (stg_debug > 1)
107279697Snon			SCSI_LOW_DEBUGGER("stg");
1073131920Smarcel#endif	/* KDB */
107467468Snon	}
107567468Snon#endif	/* STG_DEBUG */
107667468Snon
107767468Snon	/*******************************************
107867468Snon	 * reselection & nexus
107967468Snon	 *******************************************/
108067468Snon	if ((status & RESEL_PHASE_MASK)== PHASE_RESELECTED)
108167468Snon	{
108267468Snon		if (stg_reselected(sc) == EJUSTRETURN)
108379697Snon			goto out;
108467468Snon	}
108567468Snon
108679697Snon	if ((ti = slp->sl_Tnexus) == NULL)
108779697Snon		return 0;
108867468Snon
108979697Snon	derror = 0;
109067468Snon	if ((astatus & ASTAT_PARERR) != 0 && ti->ti_phase != PH_ARBSTART &&
109167468Snon	    (sc->sc_fcRinit & FCTL_PARENB) != 0)
109267468Snon	{
109367468Snon		slp->sl_error |= PARITYERR;
109479697Snon		derror = SCSI_LOW_DATA_PE;
109579697Snon		if ((status & PHASE_MASK) == MESSAGE_IN_PHASE)
109679697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
109767468Snon		else
109867468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1);
109967468Snon	}
110067468Snon
110167468Snon	/*******************************************
110267468Snon	 * aribitration & selection
110367468Snon	 *******************************************/
110467468Snon	switch (ti->ti_phase)
110567468Snon	{
110667468Snon	case PH_ARBSTART:
110767468Snon		if ((astatus & ASTAT_ARBIT) == 0)
110879697Snon		{
110979697Snon#ifdef	STG_STATICS
111079697Snon			stg_statics.arbit_fail_0 ++;
111179697Snon#endif	/* STG_STATICS */
111267468Snon			goto arb_fail;
111379697Snon		}
111467468Snon
111567468Snon		status = bus_space_read_1(iot, ioh, tmc_bstat);
111667468Snon		if ((status & BSTAT_IO) != 0)
111767468Snon		{
111867468Snon			/* XXX:
111967468Snon			 * Selection vs Reselection conflicts.
112067468Snon			 */
112167468Snon#ifdef	STG_STATICS
112279697Snon			stg_statics.arbit_fail_1 ++;
112367468Snon#endif	/* STG_STATICS */
112467468Snonarb_fail:
112567468Snon			bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
112667468Snon			stghw_bcr_write_1(sc, BCTL_BUSFREE);
112779697Snon			scsi_low_arbit_fail(slp, slp->sl_Qnexus);
112879697Snon			goto out;
112967468Snon		}
113067468Snon
113167468Snon		/*
113267468Snon		 * selection assert start.
113367468Snon		 */
113467468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
113579697Snon		scsi_low_arbit_win(slp);
113679697Snon
113779697Snon		s = splhigh();
113867468Snon		bus_space_write_1(iot, ioh, tmc_scsiid,
113967468Snon				  sc->sc_idbit | (1 << ti->ti_id));
114067468Snon		stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL);
114167468Snon		bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit);
114279697Snon		if ((stg_io_control & STG_WAIT_FOR_SELECT) != 0)
114379697Snon		{
114479697Snon			/* selection abort delay 200 + 100 micro sec */
114579697Snon			if (stghw_select_targ_wait(sc, 300) == 0)
114679697Snon			{
114779697Snon				SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
114879697Snon				stg_selection_done_and_expect_msgout(sc);
114979697Snon			}
115079697Snon		}
115179697Snon		splx(s);
115279697Snon		goto out;
115367468Snon
115467468Snon	case PH_SELSTART:
115567468Snon		if ((status & BSTAT_BSY) == 0)
115667468Snon		{
115779697Snon			/* selection timeout delay 250 ms */
115879697Snon			if (stghw_select_targ_wait(sc, 250 * 1000) != 0)
115967468Snon			{
116079697Snon				stg_disconnected(sc, ti);
116179697Snon				goto out;
116267468Snon			}
116367468Snon		}
116467468Snon
116567468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
116679697Snon		stg_selection_done_and_expect_msgout(sc);
116779697Snon		goto out;
116867468Snon
116979697Snon	case PH_SELECTED:
117079697Snon		if ((status & BSTAT_REQ) == 0)
117179697Snon			goto out;
117279697Snon		stg_target_nexus_establish(sc);
117379697Snon		break;
117479697Snon
117567468Snon	case PH_RESEL:
117679697Snon		if ((status & BSTAT_REQ) == 0)
117779697Snon			goto out;
117879697Snon
117967468Snon		/* clear a busy line */
118067468Snon		bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit);
118167468Snon		stghw_bcr_write_1(sc, sc->sc_busc);
118279697Snon		stg_target_nexus_establish(sc);
118367468Snon		if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
118467468Snon		{
118579697Snon			printf("%s: unexpected phase after reselect\n",
118679697Snon			       slp->sl_xname);
118779697Snon			slp->sl_error |= FATALIO;
118867468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
118979697Snon			goto out;
119067468Snon		}
119167468Snon		break;
119267468Snon	}
119367468Snon
119467468Snon	/*******************************************
119579697Snon	 * data phase
119667468Snon	 *******************************************/
119779697Snon	if ((slp->sl_flags & HW_PDMASTART) && STG_IS_PHASE_DATA(status) == 0)
119879697Snon	{
119979697Snon		if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
120079697Snon			stg_pio_read(sc, ti, 0);
120179697Snon
120267468Snon		stg_pdma_end(sc, ti);
120379697Snon	}
120467468Snon
120579697Snon	/*******************************************
120679697Snon	 * scsi seq
120779697Snon	 *******************************************/
120867468Snon	switch (status & PHASE_MASK)
120967468Snon	{
121067468Snon	case COMMAND_PHASE:
121179697Snon		if (stg_expect_signal(sc, COMMAND_PHASE, BSTAT_REQ) <= 0)
121279697Snon			break;
121379697Snon
121467468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
121567468Snon		if (scsi_low_cmd(slp, ti) != 0)
121679697Snon		{
121779697Snon			scsi_low_attention(slp);
121879697Snon		}
121967468Snon
122079697Snon		if (stg_xfer(sc, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen,
122179697Snon			     COMMAND_PHASE, 0) != 0)
122267468Snon		{
122379697Snon			printf("%s: CMDOUT short\n", slp->sl_xname);
122467468Snon		}
122567468Snon		break;
122667468Snon
122767468Snon	case DATA_OUT_PHASE:
122867468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
122967468Snon		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
123079697Snon		{
123179697Snon			scsi_low_attention(slp);
123279697Snon		}
123367468Snon
123467468Snon		pp = physio_proc_enter(bp);
123579697Snon		if ((sc->sc_icinit & ICTL_FIFO) != 0)
123679697Snon			stg_pio_write(sc, ti, sc->sc_wthold);
123779697Snon		else
123879697Snon			stg_pio_write(sc, ti, 0);
123967468Snon		physio_proc_leave(pp);
124067468Snon		break;
124167468Snon
124267468Snon	case DATA_IN_PHASE:
124367468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
124467468Snon		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
124579697Snon		{
124679697Snon			scsi_low_attention(slp);
124779697Snon		}
124867468Snon
124967468Snon		pp = physio_proc_enter(bp);
125079697Snon		if ((sc->sc_icinit & ICTL_FIFO) != 0)
125179697Snon			stg_pio_read(sc, ti, sc->sc_rthold);
125279697Snon		else
125379697Snon			stg_pio_read(sc, ti, 0);
125467468Snon		physio_proc_leave(pp);
125567468Snon		break;
125667468Snon
125767468Snon	case STATUS_PHASE:
125879697Snon		regv = stg_expect_signal(sc, STATUS_PHASE, BSTAT_REQ);
125979697Snon		if (regv <= 0)
126079697Snon			break;
126179697Snon
126267468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
126379697Snon		regv = bus_space_read_1(iot, ioh, tmc_sdna);
126479697Snon		if (scsi_low_statusin(slp, ti, regv | derror) != 0)
126579697Snon		{
126679697Snon			scsi_low_attention(slp);
126779697Snon		}
126879697Snon		if (regv != bus_space_read_1(iot, ioh, tmc_rdata))
126979697Snon		{
127079697Snon			printf("%s: STATIN: data mismatch\n", slp->sl_xname);
127179697Snon		}
127279697Snon		stg_negate_signal(sc, BSTAT_ACK, "statin<ACK>");
127367468Snon		break;
127467468Snon
127567468Snon	case MESSAGE_OUT_PHASE:
127679697Snon		if (stg_expect_signal(sc, MESSAGE_OUT_PHASE, BSTAT_REQ) <= 0)
127779697Snon			break;
127879697Snon
127967468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
128079697Snon		flags = (ti->ti_ophase != ti->ti_phase) ?
128179697Snon				SCSI_LOW_MSGOUT_INIT : 0;
128279697Snon		len = scsi_low_msgout(slp, ti, flags);
128379697Snon
128479697Snon		if (len > 1 && slp->sl_atten == 0)
128567468Snon		{
128679697Snon			scsi_low_attention(slp);
128779697Snon		}
128879697Snon
128979697Snon		if (stg_xfer(sc, ti->ti_msgoutstr, len, MESSAGE_OUT_PHASE,
129079697Snon			     slp->sl_clear_atten) != 0)
129179697Snon		{
129267468Snon			printf("%s: MSGOUT short\n", slp->sl_xname);
129367468Snon		}
129479697Snon		else
129579697Snon		{
129679697Snon			if (slp->sl_msgphase >= MSGPH_ABORT)
129779697Snon			{
129879697Snon				stg_disconnected(sc, ti);
129979697Snon			}
130079697Snon		}
130167468Snon		break;
130267468Snon
130367468Snon	case MESSAGE_IN_PHASE:
130479697Snon		/* confirm phase and req signal */
130579697Snon		if (stg_expect_signal(sc, MESSAGE_IN_PHASE, BSTAT_REQ) <= 0)
130679697Snon			break;
130779697Snon
130867468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
130967468Snon
131079697Snon		/* read data with NOACK */
131179697Snon		regv = bus_space_read_1(iot, ioh, tmc_sdna);
131279697Snon
131379697Snon		if (scsi_low_msgin(slp, ti, derror | regv) == 0)
131467468Snon		{
131579697Snon			if (scsi_low_is_msgout_continue(ti, 0) != 0)
131679697Snon			{
131779697Snon				scsi_low_attention(slp);
131879697Snon			}
131967468Snon		}
132067468Snon
132167468Snon		/* read data with ACK */
132279697Snon		if (regv != bus_space_read_1(iot, ioh, tmc_rdata))
132367468Snon		{
132467468Snon			printf("%s: MSGIN: data mismatch\n", slp->sl_xname);
132567468Snon		}
132667468Snon
132779697Snon		/* wait for the ack negated */
132879697Snon		stg_negate_signal(sc, BSTAT_ACK, "msgin<ACK>");
132979697Snon
133079697Snon		if (slp->sl_msgphase != 0 && slp->sl_msgphase < MSGPH_ABORT)
133167468Snon		{
133279697Snon			stg_disconnected(sc, ti);
133367468Snon		}
133467468Snon		break;
133567468Snon
133667468Snon	case BUSFREE_PHASE:
133779697Snon		printf("%s: unexpected disconnect\n", slp->sl_xname);
133879697Snon		stg_disconnected(sc, ti);
133979697Snon		break;
134067468Snon
134167468Snon	default:
134279697Snon		slp->sl_error |= FATALIO;
134379697Snon		printf("%s: unknown phase bus %x intr %x\n",
134467468Snon			slp->sl_xname, status, astatus);
134567468Snon		break;
134667468Snon	}
134767468Snon
134879697Snonout:
134979697Snon	bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
135067468Snon	return 1;
135167468Snon}
135279697Snon
135379697Snonstatic int
135479697Snonstg_timeout(sc)
135579697Snon	struct stg_softc *sc;
135679697Snon{
135779697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
135879697Snon	bus_space_tag_t iot = sc->sc_iot;
135979697Snon	bus_space_handle_t ioh = sc->sc_ioh;
136079697Snon	int tout, count;
136179697Snon	u_int8_t status;
136279697Snon
136379697Snon	if (slp->sl_Tnexus == NULL)
136479697Snon		return 0;
136579697Snon
136679697Snon	status = bus_space_read_1(iot, ioh, tmc_bstat);
136779697Snon	if ((status & PHASE_MASK) == 0)
136879697Snon	{
136979697Snon		if (sc->sc_ubf_timeout ++ == 0)
137079697Snon			return 0;
137179697Snon
137279697Snon		printf("%s: unexpected bus free detected\n", slp->sl_xname);
137379697Snon		slp->sl_error |= FATALIO;
137479697Snon		scsi_low_print(slp, slp->sl_Tnexus);
137579697Snon		stg_disconnected(sc, slp->sl_Tnexus);
137679697Snon		return 0;
137779697Snon	}
137879697Snon
137979697Snon	switch (status & PHASE_MASK)
138079697Snon	{
138179697Snon	case DATA_OUT_PHASE:
138279697Snon		if (sc->sc_dataout_timeout == 0)
138379697Snon			break;
138479697Snon		if ((status & BSTAT_REQ) == 0)
138579697Snon			break;
138679697Snon		if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0)
138779697Snon			break;
138879697Snon		if ((-- sc->sc_dataout_timeout) > 0)
138979697Snon			break;
139079697Snon
139179697Snon	        slp->sl_error |= PDMAERR;
139279697Snon		if ((slp->sl_flags & HW_WRITE_PADDING) == 0)
139379697Snon		{
139479697Snon			printf("%s: write padding required\n",
139579697Snon				slp->sl_xname);
139679697Snon			break;
139779697Snon		}
139879697Snon
139979697Snon		bus_space_write_1(iot, ioh, tmc_ictl, 0);
140079697Snon
140179697Snon		tout = STG_DELAY_MAX;
140279697Snon		while (tout --)
140379697Snon		{
140479697Snon			status = bus_space_read_1(iot, ioh, tmc_bstat);
140579697Snon			if ((status & PHASE_MASK) != DATA_OUT_PHASE)
140679697Snon				break;
140779697Snon
140879697Snon			if (bus_space_read_2(iot, ioh, tmc_fdcnt) != 0)
140979697Snon			{
141079697Snon				SCSI_LOW_DELAY(1);
141179697Snon				continue;
141279697Snon			}
141379697Snon
141479697Snon			for (count = sc->sc_maxwsize; count > 0; count --)
141579697Snon				bus_space_write_1(iot, ioh, tmc_wfifo, 0);
141679697Snon		}
141779697Snon
141879697Snon		status = bus_space_read_1(iot, ioh, tmc_bstat);
141979697Snon		if ((status & PHASE_MASK) == DATA_OUT_PHASE)
142079697Snon			sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
142179697Snon
142279697Snon		bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit);
142379697Snon		break;
142479697Snon
142579697Snon	default:
142679697Snon		break;
142779697Snon	}
142879697Snon	return 0;
142979697Snon}
1430