179697Snon/*	$NecBSD: ct.c,v 1.13.12.5 2001/06/26 07:31:53 honda Exp $	*/
2119418Sobrien
3119418Sobrien#include <sys/cdefs.h>
4119418Sobrien__FBSDID("$FreeBSD$");
573149Snyan/*	$NetBSD$	*/
673149Snyan
773149Snyan#define	CT_DEBUG
879697Snon#define	CT_IO_CONTROL_FLAGS	(CT_USE_CCSEQ | CT_FAST_INTR)
973149Snyan
10139749Simp/*-
1173149Snyan * [NetBSD for NEC PC-98 series]
1279697Snon *  Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
1373149Snyan *	NetBSD/pc98 porting staff. All rights reserved.
1473149Snyan *
1579697Snon *  Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
1673149Snyan *	Naofumi HONDA.  All rights reserved.
1773149Snyan *
1873149Snyan *  Redistribution and use in source and binary forms, with or without
1973149Snyan *  modification, are permitted provided that the following conditions
2073149Snyan *  are met:
2173149Snyan *  1. Redistributions of source code must retain the above copyright
2273149Snyan *     notice, this list of conditions and the following disclaimer.
2373149Snyan *  2. Redistributions in binary form must reproduce the above copyright
2473149Snyan *     notice, this list of conditions and the following disclaimer in the
2573149Snyan *     documentation and/or other materials provided with the distribution.
2673149Snyan *  3. The name of the author may not be used to endorse or promote products
2773149Snyan *     derived from this software without specific prior written permission.
2873149Snyan *
2973149Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
3073149Snyan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3173149Snyan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3273149Snyan * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
3373149Snyan * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3473149Snyan * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3573149Snyan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3673149Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3773149Snyan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3873149Snyan * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3973149Snyan * POSSIBILITY OF SUCH DAMAGE.
4073149Snyan */
4173149Snyan
4273149Snyan#include <sys/param.h>
4373149Snyan#include <sys/systm.h>
4473149Snyan#include <sys/kernel.h>
4579697Snon#if defined(__FreeBSD__) && __FreeBSD_version > 500001
4673149Snyan#include <sys/bio.h>
4779697Snon#endif	/* __ FreeBSD__ */
4873149Snyan#include <sys/buf.h>
4973149Snyan#include <sys/queue.h>
5073149Snyan#include <sys/malloc.h>
5173149Snyan#include <sys/errno.h>
5273149Snyan
5379697Snon#ifdef __NetBSD__
5479697Snon#include <sys/device.h>
5573149Snyan
5673149Snyan#include <machine/bus.h>
5773149Snyan#include <machine/intr.h>
5873149Snyan
5973149Snyan#include <dev/scsipi/scsi_all.h>
6073149Snyan#include <dev/scsipi/scsipi_all.h>
6173149Snyan#include <dev/scsipi/scsiconf.h>
6273149Snyan#include <dev/scsipi/scsi_disk.h>
6373149Snyan
6473149Snyan#include <machine/dvcfg.h>
6573149Snyan#include <machine/physio_proc.h>
6673149Snyan
6773149Snyan#include <i386/Cbus/dev/scsi_low.h>
6873149Snyan
6973149Snyan#include <dev/ic/wd33c93reg.h>
7073149Snyan#include <i386/Cbus/dev/ct/ctvar.h>
7179697Snon#include <i386/Cbus/dev/ct/ct_machdep.h>
7273149Snyan#endif /* __NetBSD__ */
7373149Snyan
7473149Snyan#ifdef __FreeBSD__
7573149Snyan#include <machine/bus.h>
7673149Snyan
77126928Speter#include <compat/netbsd/dvcfg.h>
78126928Speter#include <compat/netbsd/physio_proc.h>
7973149Snyan
8073149Snyan#include <cam/scsi/scsi_low.h>
8173149Snyan
8278209Snyan#include <dev/ic/wd33c93reg.h>
8373149Snyan#include <dev/ct/ctvar.h>
8479697Snon#include <dev/ct/ct_machdep.h>
8573149Snyan#endif /* __FreeBSD__ */
8673149Snyan
8779697Snon#define	CT_NTARGETS		8
8879697Snon#define	CT_NLUNS		8
8979697Snon#define	CT_RESET_DEFAULT	2000
9079697Snon#define	CT_DELAY_MAX		(2 * 1000 * 1000)
9179697Snon#define	CT_DELAY_INTERVAL	(1)
9279697Snon
9373149Snyan/***************************************************
9473149Snyan * DEBUG
9573149Snyan ***************************************************/
9673149Snyan#ifdef	CT_DEBUG
9773149Snyanint ct_debug;
9873149Snyan#endif	/* CT_DEBUG */
9973149Snyan
10073149Snyan/***************************************************
10179697Snon * IO control
10279697Snon ***************************************************/
10379697Snon#define	CT_USE_CCSEQ	0x0100
10479697Snon#define	CT_FAST_INTR	0x0200
10579697Snon
10679697Snonu_int ct_io_control = CT_IO_CONTROL_FLAGS;
10779697Snon
10879697Snon/***************************************************
10973149Snyan * default data
11073149Snyan ***************************************************/
11173149Snyanu_int8_t cthw_cmdlevel[256] = {
11273149Snyan/*   0  1   2   3   4   5   6   7   8   9   A   B   C   E   D   F */
11373149Snyan/*0*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,1  ,0  ,1  ,0  ,0  ,0  ,0  ,0  ,
11473149Snyan/*1*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
11573149Snyan/*2*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,1  ,0  ,1  ,0  ,0  ,0  ,0  ,0  ,
11673149Snyan/*3*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
11773149Snyan/*4*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
11873149Snyan/*5*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
11973149Snyan/*6*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12073149Snyan/*7*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12173149Snyan/*8*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12273149Snyan/*9*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12373149Snyan/*A*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12473149Snyan/*B*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12573149Snyan/*C*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12673149Snyan/*D*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12773149Snyan/*E*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12873149Snyan/*F*/0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,0  ,
12973149Snyan};
13073149Snyan
13179697Snon#if	0
13273149Snyan/* default synch data table */
13373149Snyan/*  A  10    6.6   5.0   4.0   3.3   2.8   2.5   2.0  M/s */
13473149Snyan/*  X  100   150   200   250   300   350   400   500  ns  */
13579697Snonstatic struct ct_synch_data ct_synch_data_FSCSI[] = {
13673149Snyan	{25, 0xa0}, {37, 0xb0}, {50, 0x20}, {62, 0xd0}, {75, 0x30},
13773149Snyan	{87, 0xf0}, {100, 0x40}, {125, 0x50}, {0, 0}
13873149Snyan};
13973149Snyan
14079697Snonstatic struct ct_synch_data ct_synch_data_SCSI[] = {
14179697Snon	{50, 0x20}, {75, 0x30}, {100, 0x40}, {125, 0x50}, {0, 0}
14279697Snon};
14379697Snon#endif
14479697Snon/***************************************************
14579697Snon * DEVICE STRUCTURE
14679697Snon ***************************************************/
14779697Snonextern struct cfdriver ct_cd;
14873149Snyan
14973149Snyan/*****************************************************************
15073149Snyan * Interface functions
15173149Snyan *****************************************************************/
15292739Salfredstatic int ct_xfer(struct ct_softc *, u_int8_t *, int, int, u_int *);
15392739Salfredstatic void ct_io_xfer(struct ct_softc *);
15492739Salfredstatic int ct_reselected(struct ct_softc *, u_int8_t);
15592739Salfredstatic void ct_phase_error(struct ct_softc *, u_int8_t);
15692739Salfredstatic int ct_start_selection(struct ct_softc *, struct slccb *);
15792739Salfredstatic int ct_msg(struct ct_softc *, struct targ_info *, u_int);
15892739Salfredstatic int ct_world_start(struct ct_softc *, int);
15992739Salfredstatic __inline void cthw_phase_bypass(struct ct_softc *, u_int8_t);
16092739Salfredstatic int cthw_chip_reset(struct ct_bus_access_handle *, int *, int, int);
16192739Salfredstatic void cthw_bus_reset(struct ct_softc *);
16292739Salfredstatic int ct_ccb_nexus_establish(struct ct_softc *);
16392739Salfredstatic int ct_lun_nexus_establish(struct ct_softc *);
16492739Salfredstatic int ct_target_nexus_establish(struct ct_softc *, int, int);
16592739Salfredstatic void cthw_attention(struct ct_softc *);
16692739Salfredstatic int ct_targ_init(struct ct_softc *, struct targ_info *, int);
16792739Salfredstatic int ct_unbusy(struct ct_softc *);
16892739Salfredstatic void ct_attention(struct ct_softc *);
16992739Salfredstatic struct ct_synch_data *ct_make_synch_table(struct ct_softc *);
17092739Salfredstatic int ct_catch_intr(struct ct_softc *);
17173149Snyan
17273149Snyanstruct scsi_low_funcs ct_funcs = {
17373149Snyan	SC_LOW_INIT_T ct_world_start,
17473149Snyan	SC_LOW_BUSRST_T cthw_bus_reset,
17573149Snyan	SC_LOW_TARG_INIT_T ct_targ_init,
17679697Snon	SC_LOW_LUN_INIT_T NULL,
17773149Snyan
17873149Snyan	SC_LOW_SELECT_T ct_start_selection,
17979697Snon	SC_LOW_NEXUS_T ct_lun_nexus_establish,
18079697Snon	SC_LOW_NEXUS_T ct_ccb_nexus_establish,
18173149Snyan
18273149Snyan	SC_LOW_ATTEN_T cthw_attention,
18373149Snyan	SC_LOW_MSG_T ct_msg,
18473149Snyan
18579697Snon	SC_LOW_TIMEOUT_T NULL,
18673149Snyan	SC_LOW_POLL_T ctintr,
18773149Snyan
18873149Snyan	NULL,	/* SC_LOW_POWER_T cthw_power, */
18973149Snyan};
19073149Snyan
19173149Snyan/**************************************************
19273149Snyan * HW functions
19373149Snyan **************************************************/
19473149Snyanstatic __inline void
195243455Snyancthw_phase_bypass(struct ct_softc *ct, u_int8_t ph)
19673149Snyan{
19779697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
19873149Snyan
19979697Snon	ct_cr_write_1(chp, wd3s_cph, ph);
20079697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_SELECT_ATN_TFR);
20173149Snyan}
20273149Snyan
20373149Snyanstatic void
204243455Snyancthw_bus_reset(struct ct_softc *ct)
20573149Snyan{
20673149Snyan
20773149Snyan	/*
20873149Snyan	 * wd33c93 does not have bus reset function.
20973149Snyan	 */
21073149Snyan	if (ct->ct_bus_reset != NULL)
21173149Snyan		((*ct->ct_bus_reset) (ct));
21273149Snyan}
21373149Snyan
21473149Snyanstatic int
215243455Snyancthw_chip_reset(struct ct_bus_access_handle *chp, int *chiprevp, int chipclk,
216243455Snyan    int hostid)
21773149Snyan{
21873149Snyan#define	CT_SELTIMEOUT_20MHz_REGV	(0x80)
21973149Snyan	u_int8_t aux, regv;
22073149Snyan	u_int seltout;
22173149Snyan	int wc;
22273149Snyan
22373149Snyan	/* issue abort cmd */
22479697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_ABORT);
22579697Snon	SCSI_LOW_DELAY(1000);	/* 1ms wait */
22679697Snon	(void) ct_stat_read_1(chp);
22779697Snon	(void) ct_cr_read_1(chp, wd3s_stat);
22873149Snyan
22973149Snyan	/* setup chip registers */
23073149Snyan	regv = 0;
23173149Snyan	seltout = CT_SELTIMEOUT_20MHz_REGV;
23273149Snyan	switch (chipclk)
23373149Snyan	{
23479697Snon	case 8:
23573149Snyan	case 10:
23673149Snyan		seltout = (seltout * chipclk) / 20;
23779697Snon		regv = IDR_FS_8_10;
23873149Snyan		break;
23973149Snyan
24079697Snon	case 12:
24173149Snyan	case 15:
24273149Snyan		seltout = (seltout * chipclk) / 20;
24373149Snyan		regv = IDR_FS_12_15;
24473149Snyan		break;
24573149Snyan
24679697Snon	case 16:
24773149Snyan	case 20:
24873149Snyan		seltout = (seltout * chipclk) / 20;
24978210Snyan		regv = IDR_FS_16_20;
25073149Snyan		break;
25173149Snyan
25273149Snyan	default:
253118594Snon		panic("ct: illegal chip clk rate");
25473149Snyan		break;
25573149Snyan	}
25673149Snyan
25779697Snon	regv |= IDR_EHP | hostid | IDR_RAF | IDR_EAF;
25879697Snon	ct_cr_write_1(chp, wd3s_oid, regv);
25979697Snon
26079697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET);
26173149Snyan	for (wc = CT_RESET_DEFAULT; wc > 0; wc --)
26273149Snyan	{
26379697Snon		aux = ct_stat_read_1(chp);
26473149Snyan		if (aux != 0xff && (aux & STR_INT))
26573149Snyan		{
26679697Snon			regv = ct_cr_read_1(chp, wd3s_stat);
26779697Snon			if (regv == BSR_RESET || regv == BSR_AFM_RESET)
26873149Snyan				break;
26973149Snyan
27079697Snon			ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET);
27173149Snyan		}
27279697Snon		SCSI_LOW_DELAY(1);
27373149Snyan	}
27473149Snyan	if (wc == 0)
27573149Snyan		return ENXIO;
27673149Snyan
27779697Snon	ct_cr_write_1(chp, wd3s_tout, seltout);
27879697Snon	ct_cr_write_1(chp, wd3s_sid, SIDR_RESEL);
27979697Snon	ct_cr_write_1(chp, wd3s_ctrl, CR_DEFAULT);
28079697Snon	ct_cr_write_1(chp, wd3s_synch, 0);
28179697Snon	if (chiprevp != NULL)
28279697Snon	{
28379697Snon		*chiprevp = CT_WD33C93;
28479697Snon		if (regv == BSR_RESET)
28579697Snon			goto out;
28673149Snyan
28779697Snon		*chiprevp = CT_WD33C93_A;
28879697Snon		ct_cr_write_1(chp, wd3s_qtag, 0xaa);
28979697Snon		if (ct_cr_read_1(chp, wd3s_qtag) != 0xaa)
29079697Snon		{
29179697Snon			ct_cr_write_1(chp, wd3s_qtag, 0x0);
29279697Snon			goto out;
29379697Snon		}
29479697Snon		ct_cr_write_1(chp, wd3s_qtag, 0x55);
29579697Snon		if (ct_cr_read_1(chp, wd3s_qtag) != 0x55)
29679697Snon		{
29779697Snon			ct_cr_write_1(chp, wd3s_qtag, 0x0);
29879697Snon			goto out;
29979697Snon		}
30079697Snon		ct_cr_write_1(chp, wd3s_qtag, 0x0);
30179697Snon		*chiprevp = CT_WD33C93_B;
30279697Snon	}
30379697Snon
30479697Snonout:
30579697Snon	(void) ct_stat_read_1(chp);
30679697Snon	(void) ct_cr_read_1(chp, wd3s_stat);
30773149Snyan	return 0;
30873149Snyan}
30973149Snyan
31079697Snonstatic struct ct_synch_data *
311243455Snyanct_make_synch_table(struct ct_softc *ct)
31279697Snon{
31379697Snon	struct ct_synch_data *sdtp, *sdp;
31479697Snon	u_int base, i, period;
31579697Snon
31679697Snon	sdtp = sdp = &ct->sc_default_sdt[0];
31779697Snon
31879697Snon	if ((ct->sc_chipclk % 5) == 0)
31979697Snon		base = 1000 / (5 * 2);	/* 5 MHz type */
32079697Snon	else
32179697Snon		base = 1000 / (4 * 2);	/* 4 MHz type */
32279697Snon
32379697Snon	if (ct->sc_chiprev >= CT_WD33C93_B)
32479697Snon	{
32579697Snon		/* fast scsi */
32679697Snon		for (i = 2; i < 8; i ++, sdp ++)
32779697Snon		{
32879697Snon			period = (base * i) / 2;
32979697Snon			if (period >= 200)	/* 5 MHz */
33079697Snon				break;
33179697Snon			sdp->cs_period = period / 4;
33279697Snon			sdp->cs_syncr = (i * 0x10) | 0x80;
33379697Snon		}
33479697Snon	}
33579697Snon
33679697Snon	for (i = 2; i < 8; i ++, sdp ++)
33779697Snon	{
33879697Snon		period = (base * i);
33979697Snon		if (period > 500)		/* 2 MHz */
34079697Snon			break;
34179697Snon		sdp->cs_period = period / 4;
34279697Snon		sdp->cs_syncr = (i * 0x10);
34379697Snon	}
34479697Snon
34579697Snon	sdp->cs_period = 0;
34679697Snon	sdp->cs_syncr = 0;
34779697Snon	return sdtp;
34879697Snon}
34979697Snon
35073149Snyan/**************************************************
35173149Snyan * Attach & Probe
35273149Snyan **************************************************/
35373149Snyanint
354243455Snyanctprobesubr(struct ct_bus_access_handle *chp, u_int dvcfg, int hsid,
355243455Snyan    u_int chipclk, int *chiprevp)
35673149Snyan{
35773149Snyan
35873149Snyan#if	0
35979697Snon	if ((ct_stat_read_1(chp) & STR_BSY) != 0)
36073149Snyan		return 0;
36173149Snyan#endif
36279697Snon	if (cthw_chip_reset(chp, chiprevp, chipclk, hsid) != 0)
36373149Snyan		return 0;
36473149Snyan	return 1;
36573149Snyan}
36673149Snyan
36773149Snyanint
36873149Snyanctprint(aux, name)
36973149Snyan	void *aux;
37073149Snyan	const char *name;
37173149Snyan{
37273149Snyan
37373149Snyan	if (name != NULL)
37473149Snyan		printf("%s: scsibus ", name);
37573149Snyan	return UNCONF;
37673149Snyan}
37773149Snyan
37873149Snyanvoid
379243455Snyanctattachsubr(struct ct_softc *ct)
38073149Snyan{
38173149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
38273149Snyan
38379697Snon	ct->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
38473149Snyan	slp->sl_funcs = &ct_funcs;
38579697Snon	slp->sl_flags |= HW_READ_PADDING;
38679697Snon	(void) scsi_low_attach(slp, 0, CT_NTARGETS, CT_NLUNS,
38779697Snon			       sizeof(struct ct_targ_info), 0);
38873149Snyan}
38973149Snyan
39073149Snyan/**************************************************
39173149Snyan * SCSI LOW interface functions
39273149Snyan **************************************************/
39373149Snyanstatic void
394243455Snyancthw_attention(struct ct_softc *ct)
39573149Snyan{
39679697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
39773149Snyan
39879697Snon	ct->sc_atten = 1;
39979697Snon	if ((ct_stat_read_1(chp) & (STR_BSY | STR_CIP)) != 0)
40073149Snyan		return;
40173149Snyan
40279697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_ASSERT_ATN);
40379697Snon	SCSI_LOW_DELAY(10);
40479697Snon	if ((ct_stat_read_1(chp) & STR_LCI) == 0)
40579697Snon		ct->sc_atten = 0;
40679697Snon	ct_unbusy(ct);
40779697Snon	return;
40879697Snon}
40979697Snon
41079697Snonstatic void
411243455Snyanct_attention(struct ct_softc *ct)
41279697Snon{
41379697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
41479697Snon
41579697Snon	if (slp->sl_atten == 0)
41673149Snyan	{
41779697Snon		ct_unbusy(ct);
41879697Snon		scsi_low_attention(slp);
41973149Snyan	}
42079697Snon	else if (ct->sc_atten != 0)
42179697Snon	{
42279697Snon		ct_unbusy(ct);
42379697Snon		cthw_attention(ct);
42479697Snon	}
42573149Snyan}
42673149Snyan
42773149Snyanstatic int
428243455Snyanct_targ_init(struct ct_softc *ct, struct targ_info *ti, int action)
42973149Snyan{
43073149Snyan	struct ct_targ_info *cti = (void *) ti;
43173149Snyan
43279697Snon	if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
43373149Snyan	{
43479697Snon		if (ct->sc_sdp == NULL)
43579697Snon		{
43679697Snon			ct->sc_sdp = ct_make_synch_table(ct);
43779697Snon		}
43879697Snon
43979697Snon		switch (ct->sc_chiprev)
44079697Snon		{
44179697Snon		default:
44279697Snon			ti->ti_maxsynch.offset = 5;
44379697Snon			break;
44479697Snon
44579697Snon		case CT_WD33C93_A:
44679697Snon		case CT_AM33C93_A:
44779697Snon			ti->ti_maxsynch.offset = 12;
44879697Snon			break;
44979697Snon
45079697Snon		case CT_WD33C93_B:
45179697Snon		case CT_WD33C93_C:
45279697Snon			ti->ti_maxsynch.offset = 12;
45379697Snon			break;
45479697Snon		}
45579697Snon
45679697Snon		ti->ti_maxsynch.period = ct->sc_sdp[0].cs_period;
45779697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
45879697Snon		cti->cti_syncreg = 0;
45973149Snyan	}
46073149Snyan
46173149Snyan	return 0;
46273149Snyan}
46373149Snyan
46473149Snyanstatic int
465243455Snyanct_world_start(struct ct_softc *ct, int fdone)
46673149Snyan{
46773149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
46879697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
46973149Snyan
47073149Snyan	if (ct->sc_sdp == NULL)
47179697Snon	{
47279697Snon		ct->sc_sdp = ct_make_synch_table(ct);
47379697Snon	}
47473149Snyan
47573149Snyan	if (slp->sl_cfgflags & CFG_NOPARITY)
47673149Snyan		ct->sc_creg = CR_DEFAULT;
47773149Snyan	else
47873149Snyan		ct->sc_creg = CR_DEFAULT_HP;
47973149Snyan
48073149Snyan	if (ct->sc_dma & CT_DMA_DMASTART)
48173149Snyan		(*ct->ct_dma_xfer_stop) (ct);
48273149Snyan	if (ct->sc_dma & CT_DMA_PIOSTART)
48373149Snyan		(*ct->ct_pio_xfer_stop) (ct);
48473149Snyan	ct->sc_dma = 0;
48573149Snyan	ct->sc_atten = 0;
48673149Snyan
48779697Snon	cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid);
48873149Snyan	scsi_low_bus_reset(slp);
48979697Snon	cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid);
49073149Snyan
49173149Snyan	SOFT_INTR_REQUIRED(slp);
49273149Snyan	return 0;
49373149Snyan}
49473149Snyan
49573149Snyanstatic int
496243455Snyanct_start_selection(struct ct_softc *ct, struct slccb *cb)
49773149Snyan{
49873149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
49979697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
50079697Snon
50179697Snon	struct targ_info *ti = slp->sl_Tnexus;
50279697Snon	struct lun_info *li = slp->sl_Lnexus;
50379697Snon	int s, satok;
50473149Snyan	u_int8_t cmd;
50573149Snyan
50679697Snon	ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
50773149Snyan	ct->sc_atten = 0;
50879697Snon	satok = 0;
50979697Snon
51079697Snon	if (scsi_low_is_disconnect_ok(cb) != 0)
51179697Snon	{
51279697Snon		if (ct->sc_chiprev >= CT_WD33C93_A)
51379697Snon			satok = 1;
51479697Snon		else if (cthw_cmdlevel[slp->sl_scp.scp_cmd[0]] != 0)
51579697Snon			satok = 1;
51679697Snon	}
51779697Snon
51879697Snon	if (satok != 0 &&
51979697Snon	    scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0)
52073149Snyan	{
52179697Snon		cmd = WD3S_SELECT_ATN_TFR;
52273149Snyan		ct->sc_satgo = CT_SAT_GOING;
52373149Snyan	}
52473149Snyan	else
52573149Snyan	{
52673149Snyan		cmd = WD3S_SELECT_ATN;
52773149Snyan		ct->sc_satgo = 0;
52873149Snyan	}
52973149Snyan
53079697Snon	if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) != 0)
53173149Snyan		return SCSI_LOW_START_FAIL;
53273149Snyan
53373149Snyan	if ((ct->sc_satgo & CT_SAT_GOING) != 0)
53479697Snon	{
53579697Snon		(void) scsi_low_msgout(slp, ti, SCSI_LOW_MSGOUT_INIT);
53679697Snon		scsi_low_cmd(slp, ti);
53779697Snon		ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen);
53879697Snon		ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
53979697Snon	}
54079697Snon	else
54179697Snon	{
54279697Snon		/* anyway attention assert */
54379697Snon		SCSI_LOW_ASSERT_ATN(slp);
54479697Snon	}
54573149Snyan
54679697Snon	ct_target_nexus_establish(ct, li->li_lun, slp->sl_scp.scp_direction);
54779697Snon
54873149Snyan	s = splhigh();
54979697Snon	if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) == 0)
55073149Snyan	{
55173149Snyan		/* XXX:
55273149Snyan		 * Reload a lun again here.
55373149Snyan		 */
55479697Snon		ct_cr_write_1(chp, wd3s_lun, li->li_lun);
55579697Snon		ct_cr_write_1(chp, wd3s_cmd, cmd);
55679697Snon		if ((ct_stat_read_1(chp) & STR_LCI) == 0)
55773149Snyan		{
55873149Snyan			splx(s);
55973149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
56073149Snyan			return SCSI_LOW_START_OK;
56173149Snyan		}
56273149Snyan	}
56373149Snyan	splx(s);
56473149Snyan	return SCSI_LOW_START_FAIL;
56573149Snyan}
56673149Snyan
56773149Snyanstatic int
568243455Snyanct_msg(struct ct_softc *ct, struct targ_info *ti, u_int msg)
56973149Snyan{
57079697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
57173149Snyan	struct ct_targ_info *cti = (void *) ti;
57273149Snyan	struct ct_synch_data *csp = ct->sc_sdp;
57373149Snyan	u_int offset, period;
57479697Snon	int error;
57573149Snyan
57679697Snon	if ((msg & SCSI_LOW_MSG_WIDE) != 0)
57779697Snon	{
57879697Snon		if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
57979697Snon		{
58079697Snon			ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
58179697Snon			return EINVAL;
58279697Snon		}
58373149Snyan		return 0;
58479697Snon	}
58573149Snyan
58679697Snon	if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
58779697Snon		return 0;
58879697Snon
58973149Snyan	offset = ti->ti_maxsynch.offset;
59073149Snyan	period = ti->ti_maxsynch.period;
59173149Snyan	for ( ; csp->cs_period != 0; csp ++)
59273149Snyan	{
59373149Snyan		if (period == csp->cs_period)
59473149Snyan			break;
59573149Snyan	}
59673149Snyan
59773149Snyan	if (ti->ti_maxsynch.period != 0 && csp->cs_period == 0)
59873149Snyan	{
59973149Snyan		ti->ti_maxsynch.period = 0;
60073149Snyan		ti->ti_maxsynch.offset = 0;
60173149Snyan		cti->cti_syncreg = 0;
60279697Snon		error = EINVAL;
60373149Snyan	}
60479697Snon	else
60579697Snon	{
60679697Snon		cti->cti_syncreg = ((offset & 0x0f) | csp->cs_syncr);
60779697Snon		error = 0;
60879697Snon	}
60973149Snyan
61073149Snyan	if (ct->ct_synch_setup != 0)
61179697Snon		(*ct->ct_synch_setup) (ct, ti);
61279697Snon	ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg);
61379697Snon	return error;
61473149Snyan}
61573149Snyan
61673149Snyan/*************************************************
61773149Snyan * <DATA PHASE>
61873149Snyan *************************************************/
61973149Snyanstatic int
620243455Snyanct_xfer(struct ct_softc *ct, u_int8_t *data, int len, int direction,
621243455Snyan    u_int *statp)
62273149Snyan{
62379697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
62473149Snyan	int wc;
62573149Snyan	register u_int8_t aux;
62673149Snyan
62779697Snon	*statp = 0;
62873149Snyan	if (len == 1)
62973149Snyan	{
63079697Snon		ct_cr_write_1(chp, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO);
63173149Snyan	}
63273149Snyan	else
63373149Snyan	{
63479697Snon		cthw_set_count(chp, len);
63579697Snon		ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
63673149Snyan	}
63773149Snyan
63879697Snon	aux = ct_stat_read_1(chp);
63973149Snyan	if ((aux & STR_LCI) != 0)
64073149Snyan	{
64179697Snon		cthw_set_count(chp, 0);
64273149Snyan		return len;
64373149Snyan	}
64473149Snyan
64579697Snon	for (wc = 0; wc < ct->sc_tmaxcnt; wc ++)
64673149Snyan	{
64773149Snyan		/* check data ready */
64873149Snyan		if ((aux & (STR_BSY | STR_DBR)) == (STR_BSY | STR_DBR))
64973149Snyan		{
65073149Snyan			if (direction == SCSI_LOW_READ)
65179697Snon			{
65279697Snon				*data = ct_cr_read_1(chp, wd3s_data);
65379697Snon				if ((aux & STR_PE) != 0)
65479697Snon					*statp |= SCSI_LOW_DATA_PE;
65579697Snon			}
65673149Snyan			else
65779697Snon			{
65879697Snon				ct_cr_write_1(chp, wd3s_data, *data);
65979697Snon			}
66073149Snyan			len --;
66173149Snyan			if (len <= 0)
66273149Snyan				break;
66373149Snyan			data ++;
66473149Snyan		}
66579697Snon		else
66679697Snon		{
66779697Snon			SCSI_LOW_DELAY(1);
66879697Snon		}
66973149Snyan
67073149Snyan		/* check phase miss */
67179697Snon		aux = ct_stat_read_1(chp);
67273149Snyan		if ((aux & STR_INT) != 0)
67373149Snyan			break;
67473149Snyan	}
67573149Snyan	return len;
67673149Snyan}
67773149Snyan
67879697Snon#define	CT_PADDING_BUF_SIZE 32
67979697Snon
68073149Snyanstatic void
681243455Snyanct_io_xfer(struct ct_softc *ct)
68273149Snyan{
68373149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
68479697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
68573149Snyan	struct sc_p *sp = &slp->sl_scp;
68679697Snon	u_int stat;
68773149Snyan	int len;
68879697Snon	u_int8_t pbuf[CT_PADDING_BUF_SIZE];
68973149Snyan
69079697Snon	/* polling mode */
69179697Snon	ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg);
69273149Snyan
69373149Snyan	if (sp->scp_datalen <= 0)
69473149Snyan	{
69573149Snyan		slp->sl_error |= PDMAERR;
69679697Snon
69779697Snon		if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
69879697Snon			SCSI_LOW_BZERO(pbuf, CT_PADDING_BUF_SIZE);
69979697Snon		ct_xfer(ct, pbuf, CT_PADDING_BUF_SIZE,
70079697Snon			sp->scp_direction, &stat);
70173149Snyan	}
70273149Snyan	else
70379697Snon	{
70473149Snyan		len = ct_xfer(ct, sp->scp_data, sp->scp_datalen,
70579697Snon			      sp->scp_direction, &stat);
70679697Snon		sp->scp_data += (sp->scp_datalen - len);
70779697Snon		sp->scp_datalen = len;
70879697Snon	}
70973149Snyan}
71073149Snyan
71173149Snyan/**************************************************
71273149Snyan * <PHASE ERROR>
71373149Snyan **************************************************/
71473149Snyanstruct ct_err {
71573149Snyan	u_char	*pe_msg;
71673149Snyan	u_int	pe_err;
71773149Snyan	u_int	pe_errmsg;
71873149Snyan	int	pe_done;
71973149Snyan};
72073149Snyan
72173149Snyanstruct ct_err ct_cmderr[] = {
72273149Snyan/*0*/	{ "illegal cmd", FATALIO, SCSI_LOW_MSG_ABORT, 1},
72373149Snyan/*1*/	{ "unexpected bus free", FATALIO, 0, 1},
72473149Snyan/*2*/	{ NULL, SELTIMEOUTIO, 0, 1},
72573149Snyan/*3*/	{ "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0},
72673149Snyan/*4*/	{ "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0},
72773149Snyan/*5*/	{ "unknown" , FATALIO, SCSI_LOW_MSG_ABORT, 1},
72873149Snyan/*6*/	{ "miss reselection (target mode)", FATALIO, SCSI_LOW_MSG_ABORT, 0},
72973149Snyan/*7*/	{ "wrong status byte", PARITYERR, SCSI_LOW_MSG_ERROR, 0},
73073149Snyan};
73173149Snyan
73273149Snyanstatic void
733243455Snyanct_phase_error(struct ct_softc *ct, u_int8_t scsi_status)
73473149Snyan{
73573149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
73679697Snon	struct targ_info *ti = slp->sl_Tnexus;
73773149Snyan	struct ct_err *pep;
73873149Snyan	u_int msg = 0;
73973149Snyan
74073149Snyan	if ((scsi_status & BSR_CM) == BSR_CMDERR &&
74173149Snyan	    (scsi_status & BSR_PHVALID) == 0)
74273149Snyan	{
74373149Snyan		pep = &ct_cmderr[scsi_status & BSR_PM];
74473149Snyan		slp->sl_error |= pep->pe_err;
74573149Snyan		if ((pep->pe_err & PARITYERR) != 0)
74673149Snyan		{
74773149Snyan			if (ti->ti_phase == PH_MSGIN)
74873149Snyan				msg = SCSI_LOW_MSG_PARITY;
74973149Snyan			else
75073149Snyan				msg = SCSI_LOW_MSG_ERROR;
75173149Snyan		}
75273149Snyan		else
75373149Snyan			msg = pep->pe_errmsg;
75473149Snyan
75573149Snyan		if (msg != 0)
75679697Snon			scsi_low_assert_msg(slp, slp->sl_Tnexus, msg, 1);
75773149Snyan
75873149Snyan		if (pep->pe_msg != NULL)
75973149Snyan		{
76073149Snyan			printf("%s: phase error: %s",
76173149Snyan				slp->sl_xname, pep->pe_msg);
76279697Snon			scsi_low_print(slp, slp->sl_Tnexus);
76373149Snyan		}
76473149Snyan
76573149Snyan		if (pep->pe_done != 0)
76673149Snyan			scsi_low_disconnected(slp, ti);
76773149Snyan	}
76873149Snyan	else
76973149Snyan	{
77073149Snyan		slp->sl_error |= FATALIO;
77173149Snyan		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "phase error");
77273149Snyan	}
77373149Snyan}
77473149Snyan
77573149Snyan/**************************************************
77673149Snyan * ### SCSI PHASE SEQUENCER ###
77773149Snyan **************************************************/
77879697Snonstatic int
779243455Snyanct_reselected(struct ct_softc *ct, u_int8_t scsi_status)
78073149Snyan{
78173149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
78279697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
78373149Snyan	struct targ_info *ti;
78473149Snyan	u_int sid;
78579697Snon	u_int8_t regv;
78673149Snyan
78773149Snyan	ct->sc_atten = 0;
78879697Snon	ct->sc_satgo &= ~CT_SAT_GOING;
78979697Snon	regv = ct_cr_read_1(chp, wd3s_sid);
79079697Snon	if ((regv & SIDR_VALID) == 0)
79179697Snon		return EJUSTRETURN;
79279697Snon
79379697Snon	sid = regv & SIDR_IDM;
79473149Snyan	if ((ti = scsi_low_reselected(slp, sid)) == NULL)
79573149Snyan		return EJUSTRETURN;
79673149Snyan
79779697Snon	ct_target_nexus_establish(ct, 0, SCSI_LOW_READ);
79879697Snon	if (scsi_status != BSR_AFM_RESEL)
79979697Snon		return EJUSTRETURN;
80079697Snon
80179697Snon	SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
80279697Snon	regv = ct_cr_read_1(chp, wd3s_data);
80379697Snon	if (scsi_low_msgin(slp, ti, (u_int) regv) == 0)
80479697Snon	{
80579697Snon		if (scsi_low_is_msgout_continue(ti, 0) != 0)
80679697Snon		{
80779697Snon			/* XXX: scsi_low_attetion */
80879697Snon			scsi_low_attention(slp);
80979697Snon		}
81079697Snon	}
81179697Snon
81279697Snon	if (ct->sc_atten != 0)
81379697Snon	{
81479697Snon		ct_attention(ct);
81579697Snon	}
81679697Snon
81779697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK);
81873149Snyan	return EJUSTRETURN;
81973149Snyan}
82073149Snyan
82173149Snyanstatic int
822243455Snyanct_target_nexus_establish(struct ct_softc *ct, int lun, int dir)
82373149Snyan{
82479697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
82579697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
82679697Snon	struct targ_info *ti = slp->sl_Tnexus;
82773149Snyan	struct ct_targ_info *cti = (void *) ti;
82873149Snyan
82979697Snon	if (dir == SCSI_LOW_WRITE)
83079697Snon		ct_cr_write_1(chp, wd3s_did, ti->ti_id);
83173149Snyan	else
83279697Snon		ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD);
83379697Snon	ct_cr_write_1(chp, wd3s_lun, lun);
83479697Snon	ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
83579697Snon	ct_cr_write_1(chp, wd3s_cph, 0);
83679697Snon	ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg);
83779697Snon	cthw_set_count(chp, 0);
83879697Snon	return 0;
83979697Snon}
84073149Snyan
84179697Snonstatic int
842243455Snyanct_lun_nexus_establish(struct ct_softc *ct)
84379697Snon{
84479697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
84579697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
84679697Snon	struct lun_info *li = slp->sl_Lnexus;
84779697Snon
84879697Snon	ct_cr_write_1(chp, wd3s_lun, li->li_lun);
84973149Snyan	return 0;
85073149Snyan}
85173149Snyan
85279697Snonstatic int
853243455Snyanct_ccb_nexus_establish(struct ct_softc *ct)
85479697Snon{
85579697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
85679697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
85779697Snon	struct lun_info *li = slp->sl_Lnexus;
85879697Snon	struct targ_info *ti = slp->sl_Tnexus;
85979697Snon	struct ct_targ_info *cti = (void *) ti;
86079697Snon	struct slccb *cb = slp->sl_Qnexus;
86179697Snon
86279697Snon	ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
86379697Snon
86479697Snon	if ((ct->sc_satgo & CT_SAT_GOING) != 0)
86579697Snon	{
86679697Snon		ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen);
86779697Snon		ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
86879697Snon	}
86979697Snon	if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
87079697Snon		ct_cr_write_1(chp, wd3s_did, ti->ti_id);
87179697Snon	else
87279697Snon		ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD);
87379697Snon	ct_cr_write_1(chp, wd3s_lun, li->li_lun);
87479697Snon	ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg);
87579697Snon	return 0;
87679697Snon}
87779697Snon
87879697Snonstatic int
879243455Snyanct_unbusy(struct ct_softc *ct)
88079697Snon{
88179697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
88279697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
88379697Snon	int wc;
88479697Snon	register u_int8_t regv;
88579697Snon
88679697Snon	for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++)
88779697Snon	{
88879697Snon		regv = ct_stat_read_1(chp);
88979697Snon		if ((regv & (STR_BSY | STR_CIP)) == 0)
89079697Snon			return 0;
89179697Snon		if (regv == (u_int8_t) -1)
89279697Snon			return EIO;
89379697Snon
89479697Snon		SCSI_LOW_DELAY(CT_DELAY_INTERVAL);
89579697Snon	}
89679697Snon
89779697Snon	printf("%s: unbusy timeout\n", slp->sl_xname);
89879697Snon	return EBUSY;
89979697Snon}
90079697Snon
90179697Snonstatic int
902243455Snyanct_catch_intr(struct ct_softc *ct)
90379697Snon{
90479697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
90579697Snon	int wc;
90679697Snon	register u_int8_t regv;
90779697Snon
90879697Snon	for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++)
90979697Snon	{
91079697Snon		regv = ct_stat_read_1(chp);
91179697Snon		if ((regv & (STR_INT | STR_BSY | STR_CIP)) == STR_INT)
91279697Snon			return 0;
91379697Snon
91479697Snon		SCSI_LOW_DELAY(CT_DELAY_INTERVAL);
91579697Snon	}
91679697Snon	return EJUSTRETURN;
91779697Snon}
91879697Snon
91973149Snyanint
920243455Snyanctintr(void *arg)
92173149Snyan{
92273149Snyan	struct ct_softc *ct = arg;
92373149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
92479697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
92573149Snyan	struct targ_info *ti;
92673149Snyan	struct physio_proc *pp;
92773149Snyan	struct buf *bp;
92879697Snon	u_int derror, flags;
92979697Snon	int len, satgo, error;
93073149Snyan	u_int8_t scsi_status, regv;
93173149Snyan
93279697Snonagain:
93373149Snyan	if (slp->sl_flags & HW_INACTIVE)
93473149Snyan		return 0;
93573149Snyan
93673149Snyan	/**************************************************
93773149Snyan	 * Get status & bus phase
93873149Snyan	 **************************************************/
93979697Snon	if ((ct_stat_read_1(chp) & STR_INT) == 0)
94073149Snyan		return 0;
94173149Snyan
94279697Snon	scsi_status = ct_cr_read_1(chp, wd3s_stat);
94373149Snyan	if (scsi_status == ((u_int8_t) -1))
94473149Snyan		return 1;
94573149Snyan
94673149Snyan	/**************************************************
94773149Snyan	 * Check reselection, or nexus
94873149Snyan	 **************************************************/
94979697Snon	if (scsi_status == BSR_RESEL || scsi_status == BSR_AFM_RESEL)
95073149Snyan	{
95179697Snon		if (ct_reselected(ct, scsi_status) == EJUSTRETURN)
95273149Snyan			return 1;
95373149Snyan	}
95473149Snyan
95579697Snon	if ((ti = slp->sl_Tnexus) == NULL)
95673149Snyan		return 1;
95773149Snyan
95873149Snyan	/**************************************************
95973149Snyan	 * Debug section
96073149Snyan	 **************************************************/
96173149Snyan#ifdef	CT_DEBUG
96273149Snyan	if (ct_debug > 0)
96373149Snyan	{
96473149Snyan		scsi_low_print(slp, NULL);
96573149Snyan		printf("%s: scsi_status 0x%x\n\n", slp->sl_xname,
96673149Snyan		       (u_int) scsi_status);
967131911Smarcel#ifdef	KDB
96873149Snyan		if (ct_debug > 1)
96979697Snon			SCSI_LOW_DEBUGGER("ct");
970131911Smarcel#endif	/* KDB */
97173149Snyan	}
97273149Snyan#endif	/* CT_DEBUG */
97373149Snyan
97473149Snyan	/**************************************************
97573149Snyan	 * Internal scsi phase
97673149Snyan	 **************************************************/
97773149Snyan	satgo = ct->sc_satgo;
97879697Snon	ct->sc_satgo &= ~CT_SAT_GOING;
97973149Snyan
98073149Snyan	switch (ti->ti_phase)
98173149Snyan	{
98273149Snyan	case PH_SELSTART:
98373149Snyan		if ((satgo & CT_SAT_GOING) == 0)
98473149Snyan		{
98573149Snyan			if (scsi_status != BSR_SELECTED)
98673149Snyan			{
98773149Snyan				ct_phase_error(ct, scsi_status);
98873149Snyan				return 1;
98973149Snyan			}
99079697Snon			scsi_low_arbit_win(slp);
99173149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
99273149Snyan			return 1;
99373149Snyan		}
99473149Snyan		else
99573149Snyan		{
99679697Snon			scsi_low_arbit_win(slp);
99779697Snon			SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); /* XXX */
99873149Snyan		}
99973149Snyan		break;
100073149Snyan
100173149Snyan	case PH_RESEL:
100273149Snyan	    	if ((scsi_status & BSR_PHVALID) == 0 ||
100373149Snyan		    (scsi_status & BSR_PM) != BSR_MSGIN)
100473149Snyan		{
100573149Snyan			scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
100673149Snyan				 "phase miss after reselect");
100773149Snyan			return 1;
100873149Snyan		}
100973149Snyan		break;
101073149Snyan
101173149Snyan	default:
101273149Snyan		if (slp->sl_flags & HW_PDMASTART)
101373149Snyan		{
101473149Snyan			slp->sl_flags &= ~HW_PDMASTART;
101573149Snyan			if (ct->sc_dma & CT_DMA_DMASTART)
101673149Snyan			{
101773149Snyan				(*ct->ct_dma_xfer_stop) (ct);
101873149Snyan				ct->sc_dma &= ~CT_DMA_DMASTART;
101973149Snyan			}
102079697Snon			else if (ct->sc_dma & CT_DMA_PIOSTART)
102173149Snyan			{
102273149Snyan				(*ct->ct_pio_xfer_stop) (ct);
102373149Snyan				ct->sc_dma &= ~CT_DMA_PIOSTART;
102473149Snyan			}
102579697Snon			else
102679697Snon			{
102779697Snon				scsi_low_data_finish(slp);
102879697Snon			}
102973149Snyan		}
103073149Snyan		break;
103173149Snyan	}
103273149Snyan
103373149Snyan	/**************************************************
103473149Snyan	 * parse scsi phase
103573149Snyan	 **************************************************/
103673149Snyan	if (scsi_status & BSR_PHVALID)
103773149Snyan	{
103873149Snyan		/**************************************************
103973149Snyan		 * Normal SCSI phase.
104073149Snyan		 **************************************************/
104173149Snyan		if ((scsi_status & BSR_CM) == BSR_CMDABT)
104273149Snyan		{
104373149Snyan			ct_phase_error(ct, scsi_status);
104473149Snyan			return 1;
104573149Snyan		}
104673149Snyan
104773149Snyan		switch (scsi_status & BSR_PM)
104873149Snyan		{
104973149Snyan		case BSR_DATAOUT:
105073149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
105173149Snyan			if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
105279697Snon			{
105379697Snon				ct_attention(ct);
105479697Snon			}
105573149Snyan			goto common_data_phase;
105673149Snyan
105773149Snyan		case BSR_DATAIN:
105873149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
105973149Snyan			if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
106079697Snon			{
106179697Snon				ct_attention(ct);
106279697Snon			}
106373149Snyan
106473149Snyancommon_data_phase:
106579697Snon			if (slp->sl_scp.scp_datalen > 0)
106673149Snyan			{
106779697Snon				slp->sl_flags |= HW_PDMASTART;
106879697Snon				if ((ct->sc_xmode & CT_XMODE_PIO) != 0)
106979697Snon				{
107079697Snon					pp = physio_proc_enter(bp);
107179697Snon					error = (*ct->ct_pio_xfer_start) (ct);
107279697Snon					physio_proc_leave(pp);
107379697Snon					if (error == 0)
107479697Snon					{
107579697Snon						ct->sc_dma |= CT_DMA_PIOSTART;
107679697Snon						return 1;
107779697Snon					}
107879697Snon				}
107973149Snyan
108079697Snon				if ((ct->sc_xmode & CT_XMODE_DMA) != 0)
108179697Snon				{
108279697Snon					error = (*ct->ct_dma_xfer_start) (ct);
108379697Snon					if (error == 0)
108479697Snon					{
108579697Snon						ct->sc_dma |= CT_DMA_DMASTART;
108679697Snon						return 1;
108779697Snon					}
108879697Snon				}
108973149Snyan			}
109073149Snyan			else
109179697Snon			{
109279697Snon				if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
109379697Snon				{
109479697Snon					if (!(slp->sl_flags & HW_READ_PADDING))
109579697Snon					{
109679697Snon						printf("%s: read padding required\n", slp->sl_xname);
109779697Snon						return 1;
109879697Snon					}
109979697Snon				}
110079697Snon				else
110179697Snon				{
110279697Snon					if (!(slp->sl_flags & HW_WRITE_PADDING))
110379697Snon					{
110479697Snon						printf("%s: write padding required\n", slp->sl_xname);
110579697Snon						return 1;
110679697Snon					}
110779697Snon				}
110879697Snon				slp->sl_flags |= HW_PDMASTART;
110973149Snyan			}
111079697Snon
111179697Snon			ct_io_xfer(ct);
111273149Snyan			return 1;
111373149Snyan
111473149Snyan		case BSR_CMDOUT:
111573149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
111673149Snyan			if (scsi_low_cmd(slp, ti) != 0)
111779697Snon			{
111879697Snon				ct_attention(ct);
111979697Snon			}
112073149Snyan
112179697Snon			if (ct_xfer(ct, slp->sl_scp.scp_cmd,
112273149Snyan				    slp->sl_scp.scp_cmdlen,
112379697Snon				    SCSI_LOW_WRITE, &derror) != 0)
112473149Snyan			{
112573149Snyan				printf("%s: scsi cmd xfer short\n",
112673149Snyan					slp->sl_xname);
112773149Snyan			}
112873149Snyan			return 1;
112973149Snyan
113073149Snyan		case BSR_STATIN:
113173149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
113279697Snon			if ((ct_io_control & CT_USE_CCSEQ) != 0)
113373149Snyan			{
113479697Snon				if (scsi_low_is_msgout_continue(ti, 0) != 0 ||
113579697Snon				    ct->sc_atten != 0)
113679697Snon				{
113779697Snon					ct_xfer(ct, &regv, 1, SCSI_LOW_READ,
113879697Snon						&derror);
113979697Snon					scsi_low_statusin(slp, ti,
114079697Snon						  	  regv | derror);
114179697Snon				}
114279697Snon				else
114379697Snon				{
114479697Snon					ct->sc_satgo |= CT_SAT_GOING;
114579697Snon					cthw_set_count(chp, 0);
114679697Snon					cthw_phase_bypass(ct, 0x41);
114779697Snon				}
114873149Snyan			}
114973149Snyan			else
115073149Snyan			{
115179697Snon				ct_xfer(ct, &regv, 1, SCSI_LOW_READ, &derror);
115279697Snon				scsi_low_statusin(slp, ti, regv | derror);
115373149Snyan			}
115473149Snyan			return 1;
115573149Snyan
115673149Snyan		case BSR_UNSPINFO0:
115773149Snyan		case BSR_UNSPINFO1:
115873149Snyan			printf("%s: illegal bus phase (0x%x)\n", slp->sl_xname,
115973149Snyan				(u_int) scsi_status);
116073149Snyan			scsi_low_print(slp, ti);
116173149Snyan			return 1;
116273149Snyan
116373149Snyan		case BSR_MSGOUT:
116473149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
116579697Snon			flags = SCSI_LOW_MSGOUT_UNIFY;
116679697Snon		        if (ti->ti_ophase != ti->ti_phase)
116779697Snon				flags |= SCSI_LOW_MSGOUT_INIT;
116879697Snon			len = scsi_low_msgout(slp, ti, flags);
116979697Snon
117079697Snon			if (len > 1 && slp->sl_atten == 0)
117173149Snyan			{
117279697Snon				ct_attention(ct);
117379697Snon			}
117479697Snon
117579697Snon			if (ct_xfer(ct, ti->ti_msgoutstr, len,
117679697Snon				    SCSI_LOW_WRITE, &derror) != 0)
117779697Snon			{
117873149Snyan				printf("%s: scsi msgout xfer short\n",
117973149Snyan					slp->sl_xname);
118073149Snyan			}
118179697Snon			SCSI_LOW_DEASSERT_ATN(slp);
118279697Snon			ct->sc_atten = 0;
118373149Snyan			return 1;
118473149Snyan
118573149Snyan		case BSR_MSGIN:/* msg in */
118673149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
118779697Snon
118879697Snon			ct_xfer(ct, &regv, 1, SCSI_LOW_READ, &derror);
118979697Snon			if (scsi_low_msgin(slp, ti, regv | derror) == 0)
119079697Snon			{
119179697Snon				if (scsi_low_is_msgout_continue(ti, 0) != 0)
119279697Snon				{
119379697Snon					/* XXX: scsi_low_attetion */
119479697Snon					scsi_low_attention(slp);
119579697Snon				}
119679697Snon			}
119779697Snon
119879697Snon			if ((ct_io_control & CT_FAST_INTR) != 0)
119979697Snon			{
120079697Snon				if (ct_catch_intr(ct) == 0)
120179697Snon					goto again;
120279697Snon			}
120373149Snyan			return 1;
120473149Snyan		}
120573149Snyan	}
120673149Snyan	else
120773149Snyan	{
120873149Snyan		/**************************************************
120973149Snyan		 * Special SCSI phase
121073149Snyan		 **************************************************/
121173149Snyan		switch (scsi_status)
121273149Snyan		{
121373149Snyan		case BSR_SATSDP: /* SAT with save data pointer */
121473149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
121579697Snon			ct->sc_satgo |= CT_SAT_GOING;
121673149Snyan			scsi_low_msgin(slp, ti, MSG_SAVESP);
121773149Snyan			cthw_phase_bypass(ct, 0x41);
121873149Snyan			return 1;
121973149Snyan
122073149Snyan		case BSR_SATFIN: /* SAT COMPLETE */
122173149Snyan			/*
122273149Snyan			 * emulate statusin => msgin
122373149Snyan			 */
122479697Snon			SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
122579697Snon			scsi_low_statusin(slp, ti, ct_cr_read_1(chp, wd3s_lun));
122679697Snon
122773149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
122879697Snon			scsi_low_msgin(slp, ti, MSG_COMP);
122979697Snon
123073149Snyan			scsi_low_disconnected(slp, ti);
123173149Snyan			return 1;
123273149Snyan
123373149Snyan		case BSR_ACKREQ: /* negate ACK */
123473149Snyan			if (ct->sc_atten != 0)
123579697Snon			{
123679697Snon				ct_attention(ct);
123779697Snon			}
123873149Snyan
123979697Snon			ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK);
124079697Snon			if ((ct_io_control & CT_FAST_INTR) != 0)
124179697Snon			{
124279697Snon				/* XXX:
124379697Snon				 * Should clear a pending interrupt and
124479697Snon				 * sync with a next interrupt!
124579697Snon				 */
124679697Snon				ct_catch_intr(ct);
124779697Snon			}
124873149Snyan			return 1;
124973149Snyan
125073149Snyan		case BSR_DISC: /* disconnect */
125173149Snyan			if (slp->sl_msgphase == MSGPH_NULL &&
125273149Snyan			    (satgo & CT_SAT_GOING) != 0)
125373149Snyan			{
125473149Snyan				/*
125573149Snyan				 * emulate disconnect msg
125673149Snyan				 */
125773149Snyan				SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
125879697Snon				scsi_low_msgin(slp, ti, MSG_DISCON);
125973149Snyan			}
126073149Snyan			scsi_low_disconnected(slp, ti);
126173149Snyan			return 1;
126273149Snyan
126373149Snyan		default:
126473149Snyan			break;
126573149Snyan		}
126673149Snyan	}
126773149Snyan
126873149Snyan	ct_phase_error(ct, scsi_status);
126973149Snyan	return 1;
127073149Snyan}
1271