ct.c revision 118594
173149Snyan/* $FreeBSD: head/sys/dev/ct/ct.c 118594 2003-08-07 08:13:37Z non $ */
279697Snon/*	$NecBSD: ct.c,v 1.13.12.5 2001/06/26 07:31:53 honda Exp $	*/
373149Snyan/*	$NetBSD$	*/
473149Snyan
573149Snyan#define	CT_DEBUG
679697Snon#define	CT_IO_CONTROL_FLAGS	(CT_USE_CCSEQ | CT_FAST_INTR)
773149Snyan
873149Snyan/*
973149Snyan * [NetBSD for NEC PC-98 series]
1079697Snon *  Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
1173149Snyan *	NetBSD/pc98 porting staff. All rights reserved.
1273149Snyan *
1379697Snon *  Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
1473149Snyan *	Naofumi HONDA.  All rights reserved.
1573149Snyan *
1673149Snyan *  Redistribution and use in source and binary forms, with or without
1773149Snyan *  modification, are permitted provided that the following conditions
1873149Snyan *  are met:
1973149Snyan *  1. Redistributions of source code must retain the above copyright
2073149Snyan *     notice, this list of conditions and the following disclaimer.
2173149Snyan *  2. Redistributions in binary form must reproduce the above copyright
2273149Snyan *     notice, this list of conditions and the following disclaimer in the
2373149Snyan *     documentation and/or other materials provided with the distribution.
2473149Snyan *  3. The name of the author may not be used to endorse or promote products
2573149Snyan *     derived from this software without specific prior written permission.
2673149Snyan *
2773149Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2873149Snyan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2973149Snyan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3073149Snyan * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
3173149Snyan * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3273149Snyan * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3373149Snyan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3473149Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3573149Snyan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3673149Snyan * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3773149Snyan * POSSIBILITY OF SUCH DAMAGE.
3873149Snyan */
3973149Snyan
4073149Snyan#include "opt_ddb.h"
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
7773149Snyan#include <machine/dvcfg.h>
7873149Snyan#include <machine/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
19573149Snyancthw_phase_bypass(ct, ph)
19673149Snyan	struct ct_softc *ct;
19773149Snyan	u_int8_t ph;
19873149Snyan{
19979697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
20073149Snyan
20179697Snon	ct_cr_write_1(chp, wd3s_cph, ph);
20279697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_SELECT_ATN_TFR);
20373149Snyan}
20473149Snyan
20573149Snyanstatic void
20673149Snyancthw_bus_reset(ct)
20773149Snyan	struct ct_softc *ct;
20873149Snyan{
20973149Snyan
21073149Snyan	/*
21173149Snyan	 * wd33c93 does not have bus reset function.
21273149Snyan	 */
21373149Snyan	if (ct->ct_bus_reset != NULL)
21473149Snyan		((*ct->ct_bus_reset) (ct));
21573149Snyan}
21673149Snyan
21773149Snyanstatic int
21879697Snoncthw_chip_reset(chp, chiprevp, chipclk, hostid)
21979697Snon	struct ct_bus_access_handle *chp;
22079697Snon	int *chiprevp;
22173149Snyan	int chipclk, hostid;
22273149Snyan{
22373149Snyan#define	CT_SELTIMEOUT_20MHz_REGV	(0x80)
22473149Snyan	u_int8_t aux, regv;
22573149Snyan	u_int seltout;
22673149Snyan	int wc;
22773149Snyan
22873149Snyan	/* issue abort cmd */
22979697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_ABORT);
23079697Snon	SCSI_LOW_DELAY(1000);	/* 1ms wait */
23179697Snon	(void) ct_stat_read_1(chp);
23279697Snon	(void) ct_cr_read_1(chp, wd3s_stat);
23373149Snyan
23473149Snyan	/* setup chip registers */
23573149Snyan	regv = 0;
23673149Snyan	seltout = CT_SELTIMEOUT_20MHz_REGV;
23773149Snyan	switch (chipclk)
23873149Snyan	{
23979697Snon	case 8:
24073149Snyan	case 10:
24173149Snyan		seltout = (seltout * chipclk) / 20;
24279697Snon		regv = IDR_FS_8_10;
24373149Snyan		break;
24473149Snyan
24579697Snon	case 12:
24673149Snyan	case 15:
24773149Snyan		seltout = (seltout * chipclk) / 20;
24873149Snyan		regv = IDR_FS_12_15;
24973149Snyan		break;
25073149Snyan
25179697Snon	case 16:
25273149Snyan	case 20:
25373149Snyan		seltout = (seltout * chipclk) / 20;
25478210Snyan		regv = IDR_FS_16_20;
25573149Snyan		break;
25673149Snyan
25773149Snyan	default:
258118594Snon		panic("ct: illegal chip clk rate");
25973149Snyan		break;
26073149Snyan	}
26173149Snyan
26279697Snon	regv |= IDR_EHP | hostid | IDR_RAF | IDR_EAF;
26379697Snon	ct_cr_write_1(chp, wd3s_oid, regv);
26479697Snon
26579697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET);
26673149Snyan	for (wc = CT_RESET_DEFAULT; wc > 0; wc --)
26773149Snyan	{
26879697Snon		aux = ct_stat_read_1(chp);
26973149Snyan		if (aux != 0xff && (aux & STR_INT))
27073149Snyan		{
27179697Snon			regv = ct_cr_read_1(chp, wd3s_stat);
27279697Snon			if (regv == BSR_RESET || regv == BSR_AFM_RESET)
27373149Snyan				break;
27473149Snyan
27579697Snon			ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET);
27673149Snyan		}
27779697Snon		SCSI_LOW_DELAY(1);
27873149Snyan	}
27973149Snyan	if (wc == 0)
28073149Snyan		return ENXIO;
28173149Snyan
28279697Snon	ct_cr_write_1(chp, wd3s_tout, seltout);
28379697Snon	ct_cr_write_1(chp, wd3s_sid, SIDR_RESEL);
28479697Snon	ct_cr_write_1(chp, wd3s_ctrl, CR_DEFAULT);
28579697Snon	ct_cr_write_1(chp, wd3s_synch, 0);
28679697Snon	if (chiprevp != NULL)
28779697Snon	{
28879697Snon		*chiprevp = CT_WD33C93;
28979697Snon		if (regv == BSR_RESET)
29079697Snon			goto out;
29173149Snyan
29279697Snon		*chiprevp = CT_WD33C93_A;
29379697Snon		ct_cr_write_1(chp, wd3s_qtag, 0xaa);
29479697Snon		if (ct_cr_read_1(chp, wd3s_qtag) != 0xaa)
29579697Snon		{
29679697Snon			ct_cr_write_1(chp, wd3s_qtag, 0x0);
29779697Snon			goto out;
29879697Snon		}
29979697Snon		ct_cr_write_1(chp, wd3s_qtag, 0x55);
30079697Snon		if (ct_cr_read_1(chp, wd3s_qtag) != 0x55)
30179697Snon		{
30279697Snon			ct_cr_write_1(chp, wd3s_qtag, 0x0);
30379697Snon			goto out;
30479697Snon		}
30579697Snon		ct_cr_write_1(chp, wd3s_qtag, 0x0);
30679697Snon		*chiprevp = CT_WD33C93_B;
30779697Snon	}
30879697Snon
30979697Snonout:
31079697Snon	(void) ct_stat_read_1(chp);
31179697Snon	(void) ct_cr_read_1(chp, wd3s_stat);
31273149Snyan	return 0;
31373149Snyan}
31473149Snyan
31579697Snonstatic struct ct_synch_data *
31679697Snonct_make_synch_table(ct)
31779697Snon	struct ct_softc *ct;
31879697Snon{
31979697Snon	struct ct_synch_data *sdtp, *sdp;
32079697Snon	u_int base, i, period;
32179697Snon
32279697Snon	sdtp = sdp = &ct->sc_default_sdt[0];
32379697Snon
32479697Snon	if ((ct->sc_chipclk % 5) == 0)
32579697Snon		base = 1000 / (5 * 2);	/* 5 MHz type */
32679697Snon	else
32779697Snon		base = 1000 / (4 * 2);	/* 4 MHz type */
32879697Snon
32979697Snon	if (ct->sc_chiprev >= CT_WD33C93_B)
33079697Snon	{
33179697Snon		/* fast scsi */
33279697Snon		for (i = 2; i < 8; i ++, sdp ++)
33379697Snon		{
33479697Snon			period = (base * i) / 2;
33579697Snon			if (period >= 200)	/* 5 MHz */
33679697Snon				break;
33779697Snon			sdp->cs_period = period / 4;
33879697Snon			sdp->cs_syncr = (i * 0x10) | 0x80;
33979697Snon		}
34079697Snon	}
34179697Snon
34279697Snon	for (i = 2; i < 8; i ++, sdp ++)
34379697Snon	{
34479697Snon		period = (base * i);
34579697Snon		if (period > 500)		/* 2 MHz */
34679697Snon			break;
34779697Snon		sdp->cs_period = period / 4;
34879697Snon		sdp->cs_syncr = (i * 0x10);
34979697Snon	}
35079697Snon
35179697Snon	sdp->cs_period = 0;
35279697Snon	sdp->cs_syncr = 0;
35379697Snon	return sdtp;
35479697Snon}
35579697Snon
35673149Snyan/**************************************************
35773149Snyan * Attach & Probe
35873149Snyan **************************************************/
35973149Snyanint
36079697Snonctprobesubr(chp, dvcfg, hsid, chipclk, chiprevp)
36179697Snon	struct ct_bus_access_handle *chp;
36273149Snyan	u_int dvcfg, chipclk;
36373149Snyan	int hsid;
36479697Snon	int *chiprevp;
36573149Snyan{
36673149Snyan
36773149Snyan#if	0
36879697Snon	if ((ct_stat_read_1(chp) & STR_BSY) != 0)
36973149Snyan		return 0;
37073149Snyan#endif
37179697Snon	if (cthw_chip_reset(chp, chiprevp, chipclk, hsid) != 0)
37273149Snyan		return 0;
37373149Snyan	return 1;
37473149Snyan}
37573149Snyan
37673149Snyanint
37773149Snyanctprint(aux, name)
37873149Snyan	void *aux;
37973149Snyan	const char *name;
38073149Snyan{
38173149Snyan
38273149Snyan	if (name != NULL)
38373149Snyan		printf("%s: scsibus ", name);
38473149Snyan	return UNCONF;
38573149Snyan}
38673149Snyan
38773149Snyanvoid
38873149Snyanctattachsubr(ct)
38973149Snyan	struct ct_softc *ct;
39073149Snyan{
39173149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
39273149Snyan
39379697Snon	ct->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
39473149Snyan	slp->sl_funcs = &ct_funcs;
39579697Snon	slp->sl_flags |= HW_READ_PADDING;
39679697Snon	(void) scsi_low_attach(slp, 0, CT_NTARGETS, CT_NLUNS,
39779697Snon			       sizeof(struct ct_targ_info), 0);
39873149Snyan}
39973149Snyan
40073149Snyan/**************************************************
40173149Snyan * SCSI LOW interface functions
40273149Snyan **************************************************/
40373149Snyanstatic void
40473149Snyancthw_attention(ct)
40573149Snyan	struct ct_softc *ct;
40673149Snyan{
40779697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
40873149Snyan
40979697Snon	ct->sc_atten = 1;
41079697Snon	if ((ct_stat_read_1(chp) & (STR_BSY | STR_CIP)) != 0)
41173149Snyan		return;
41273149Snyan
41379697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_ASSERT_ATN);
41479697Snon	SCSI_LOW_DELAY(10);
41579697Snon	if ((ct_stat_read_1(chp) & STR_LCI) == 0)
41679697Snon		ct->sc_atten = 0;
41779697Snon	ct_unbusy(ct);
41879697Snon	return;
41979697Snon}
42079697Snon
42179697Snonstatic void
42279697Snonct_attention(ct)
42379697Snon	struct ct_softc *ct;
42479697Snon{
42579697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
42679697Snon
42779697Snon	if (slp->sl_atten == 0)
42873149Snyan	{
42979697Snon		ct_unbusy(ct);
43079697Snon		scsi_low_attention(slp);
43173149Snyan	}
43279697Snon	else if (ct->sc_atten != 0)
43379697Snon	{
43479697Snon		ct_unbusy(ct);
43579697Snon		cthw_attention(ct);
43679697Snon	}
43773149Snyan}
43873149Snyan
43973149Snyanstatic int
44079697Snonct_targ_init(ct, ti, action)
44173149Snyan	struct ct_softc *ct;
44273149Snyan	struct targ_info *ti;
44379697Snon	int action;
44473149Snyan{
44573149Snyan	struct ct_targ_info *cti = (void *) ti;
44673149Snyan
44779697Snon	if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
44873149Snyan	{
44979697Snon		if (ct->sc_sdp == NULL)
45079697Snon		{
45179697Snon			ct->sc_sdp = ct_make_synch_table(ct);
45279697Snon		}
45379697Snon
45479697Snon		switch (ct->sc_chiprev)
45579697Snon		{
45679697Snon		default:
45779697Snon			ti->ti_maxsynch.offset = 5;
45879697Snon			break;
45979697Snon
46079697Snon		case CT_WD33C93_A:
46179697Snon		case CT_AM33C93_A:
46279697Snon			ti->ti_maxsynch.offset = 12;
46379697Snon			break;
46479697Snon
46579697Snon		case CT_WD33C93_B:
46679697Snon		case CT_WD33C93_C:
46779697Snon			ti->ti_maxsynch.offset = 12;
46879697Snon			break;
46979697Snon		}
47079697Snon
47179697Snon		ti->ti_maxsynch.period = ct->sc_sdp[0].cs_period;
47279697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
47379697Snon		cti->cti_syncreg = 0;
47473149Snyan	}
47573149Snyan
47673149Snyan	return 0;
47773149Snyan}
47873149Snyan
47973149Snyanstatic int
48073149Snyanct_world_start(ct, fdone)
48173149Snyan	struct ct_softc *ct;
48273149Snyan	int fdone;
48373149Snyan{
48473149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
48579697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
48673149Snyan
48773149Snyan	if (ct->sc_sdp == NULL)
48879697Snon	{
48979697Snon		ct->sc_sdp = ct_make_synch_table(ct);
49079697Snon	}
49173149Snyan
49273149Snyan	if (slp->sl_cfgflags & CFG_NOPARITY)
49373149Snyan		ct->sc_creg = CR_DEFAULT;
49473149Snyan	else
49573149Snyan		ct->sc_creg = CR_DEFAULT_HP;
49673149Snyan
49773149Snyan	if (ct->sc_dma & CT_DMA_DMASTART)
49873149Snyan		(*ct->ct_dma_xfer_stop) (ct);
49973149Snyan	if (ct->sc_dma & CT_DMA_PIOSTART)
50073149Snyan		(*ct->ct_pio_xfer_stop) (ct);
50173149Snyan	ct->sc_dma = 0;
50273149Snyan	ct->sc_atten = 0;
50373149Snyan
50479697Snon	cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid);
50573149Snyan	scsi_low_bus_reset(slp);
50679697Snon	cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid);
50773149Snyan
50873149Snyan	SOFT_INTR_REQUIRED(slp);
50973149Snyan	return 0;
51073149Snyan}
51173149Snyan
51273149Snyanstatic int
51373149Snyanct_start_selection(ct, cb)
51473149Snyan	struct ct_softc *ct;
51573149Snyan	struct slccb *cb;
51673149Snyan{
51773149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
51879697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
51979697Snon
52079697Snon	struct targ_info *ti = slp->sl_Tnexus;
52179697Snon	struct lun_info *li = slp->sl_Lnexus;
52279697Snon	int s, satok;
52373149Snyan	u_int8_t cmd;
52473149Snyan
52579697Snon	ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
52673149Snyan	ct->sc_atten = 0;
52779697Snon	satok = 0;
52879697Snon
52979697Snon	if (scsi_low_is_disconnect_ok(cb) != 0)
53079697Snon	{
53179697Snon		if (ct->sc_chiprev >= CT_WD33C93_A)
53279697Snon			satok = 1;
53379697Snon		else if (cthw_cmdlevel[slp->sl_scp.scp_cmd[0]] != 0)
53479697Snon			satok = 1;
53579697Snon	}
53679697Snon
53779697Snon	if (satok != 0 &&
53879697Snon	    scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0)
53973149Snyan	{
54079697Snon		cmd = WD3S_SELECT_ATN_TFR;
54173149Snyan		ct->sc_satgo = CT_SAT_GOING;
54273149Snyan	}
54373149Snyan	else
54473149Snyan	{
54573149Snyan		cmd = WD3S_SELECT_ATN;
54673149Snyan		ct->sc_satgo = 0;
54773149Snyan	}
54873149Snyan
54979697Snon	if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) != 0)
55073149Snyan		return SCSI_LOW_START_FAIL;
55173149Snyan
55273149Snyan	if ((ct->sc_satgo & CT_SAT_GOING) != 0)
55379697Snon	{
55479697Snon		(void) scsi_low_msgout(slp, ti, SCSI_LOW_MSGOUT_INIT);
55579697Snon		scsi_low_cmd(slp, ti);
55679697Snon		ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen);
55779697Snon		ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
55879697Snon	}
55979697Snon	else
56079697Snon	{
56179697Snon		/* anyway attention assert */
56279697Snon		SCSI_LOW_ASSERT_ATN(slp);
56379697Snon	}
56473149Snyan
56579697Snon	ct_target_nexus_establish(ct, li->li_lun, slp->sl_scp.scp_direction);
56679697Snon
56773149Snyan	s = splhigh();
56879697Snon	if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) == 0)
56973149Snyan	{
57073149Snyan		/* XXX:
57173149Snyan		 * Reload a lun again here.
57273149Snyan		 */
57379697Snon		ct_cr_write_1(chp, wd3s_lun, li->li_lun);
57479697Snon		ct_cr_write_1(chp, wd3s_cmd, cmd);
57579697Snon		if ((ct_stat_read_1(chp) & STR_LCI) == 0)
57673149Snyan		{
57773149Snyan			splx(s);
57873149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
57973149Snyan			return SCSI_LOW_START_OK;
58073149Snyan		}
58173149Snyan	}
58273149Snyan	splx(s);
58373149Snyan	return SCSI_LOW_START_FAIL;
58473149Snyan}
58573149Snyan
58673149Snyanstatic int
58773149Snyanct_msg(ct, ti, msg)
58873149Snyan	struct ct_softc *ct;
58973149Snyan	struct targ_info *ti;
59073149Snyan	u_int msg;
59173149Snyan{
59279697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
59373149Snyan	struct ct_targ_info *cti = (void *) ti;
59473149Snyan	struct ct_synch_data *csp = ct->sc_sdp;
59573149Snyan	u_int offset, period;
59679697Snon	int error;
59773149Snyan
59879697Snon	if ((msg & SCSI_LOW_MSG_WIDE) != 0)
59979697Snon	{
60079697Snon		if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
60179697Snon		{
60279697Snon			ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
60379697Snon			return EINVAL;
60479697Snon		}
60573149Snyan		return 0;
60679697Snon	}
60773149Snyan
60879697Snon	if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
60979697Snon		return 0;
61079697Snon
61173149Snyan	offset = ti->ti_maxsynch.offset;
61273149Snyan	period = ti->ti_maxsynch.period;
61373149Snyan	for ( ; csp->cs_period != 0; csp ++)
61473149Snyan	{
61573149Snyan		if (period == csp->cs_period)
61673149Snyan			break;
61773149Snyan	}
61873149Snyan
61973149Snyan	if (ti->ti_maxsynch.period != 0 && csp->cs_period == 0)
62073149Snyan	{
62173149Snyan		ti->ti_maxsynch.period = 0;
62273149Snyan		ti->ti_maxsynch.offset = 0;
62373149Snyan		cti->cti_syncreg = 0;
62479697Snon		error = EINVAL;
62573149Snyan	}
62679697Snon	else
62779697Snon	{
62879697Snon		cti->cti_syncreg = ((offset & 0x0f) | csp->cs_syncr);
62979697Snon		error = 0;
63079697Snon	}
63173149Snyan
63273149Snyan	if (ct->ct_synch_setup != 0)
63379697Snon		(*ct->ct_synch_setup) (ct, ti);
63479697Snon	ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg);
63579697Snon	return error;
63673149Snyan}
63773149Snyan
63873149Snyan/*************************************************
63973149Snyan * <DATA PHASE>
64073149Snyan *************************************************/
64173149Snyanstatic int
64279697Snonct_xfer(ct, data, len, direction, statp)
64373149Snyan	struct ct_softc *ct;
64473149Snyan	u_int8_t *data;
64573149Snyan	int len, direction;
64679697Snon	u_int *statp;
64773149Snyan{
64879697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
64973149Snyan	int wc;
65073149Snyan	register u_int8_t aux;
65173149Snyan
65279697Snon	*statp = 0;
65373149Snyan	if (len == 1)
65473149Snyan	{
65579697Snon		ct_cr_write_1(chp, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO);
65673149Snyan	}
65773149Snyan	else
65873149Snyan	{
65979697Snon		cthw_set_count(chp, len);
66079697Snon		ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO);
66173149Snyan	}
66273149Snyan
66379697Snon	aux = ct_stat_read_1(chp);
66473149Snyan	if ((aux & STR_LCI) != 0)
66573149Snyan	{
66679697Snon		cthw_set_count(chp, 0);
66773149Snyan		return len;
66873149Snyan	}
66973149Snyan
67079697Snon	for (wc = 0; wc < ct->sc_tmaxcnt; wc ++)
67173149Snyan	{
67273149Snyan		/* check data ready */
67373149Snyan		if ((aux & (STR_BSY | STR_DBR)) == (STR_BSY | STR_DBR))
67473149Snyan		{
67573149Snyan			if (direction == SCSI_LOW_READ)
67679697Snon			{
67779697Snon				*data = ct_cr_read_1(chp, wd3s_data);
67879697Snon				if ((aux & STR_PE) != 0)
67979697Snon					*statp |= SCSI_LOW_DATA_PE;
68079697Snon			}
68173149Snyan			else
68279697Snon			{
68379697Snon				ct_cr_write_1(chp, wd3s_data, *data);
68479697Snon			}
68573149Snyan			len --;
68673149Snyan			if (len <= 0)
68773149Snyan				break;
68873149Snyan			data ++;
68973149Snyan		}
69079697Snon		else
69179697Snon		{
69279697Snon			SCSI_LOW_DELAY(1);
69379697Snon		}
69473149Snyan
69573149Snyan		/* check phase miss */
69679697Snon		aux = ct_stat_read_1(chp);
69773149Snyan		if ((aux & STR_INT) != 0)
69873149Snyan			break;
69973149Snyan	}
70073149Snyan	return len;
70173149Snyan}
70273149Snyan
70379697Snon#define	CT_PADDING_BUF_SIZE 32
70479697Snon
70573149Snyanstatic void
70673149Snyanct_io_xfer(ct)
70773149Snyan	struct ct_softc *ct;
70873149Snyan{
70973149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
71079697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
71173149Snyan	struct sc_p *sp = &slp->sl_scp;
71279697Snon	u_int stat;
71373149Snyan	int len;
71479697Snon	u_int8_t pbuf[CT_PADDING_BUF_SIZE];
71573149Snyan
71679697Snon	/* polling mode */
71779697Snon	ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg);
71873149Snyan
71973149Snyan	if (sp->scp_datalen <= 0)
72073149Snyan	{
72173149Snyan		slp->sl_error |= PDMAERR;
72279697Snon
72379697Snon		if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
72479697Snon			SCSI_LOW_BZERO(pbuf, CT_PADDING_BUF_SIZE);
72579697Snon		ct_xfer(ct, pbuf, CT_PADDING_BUF_SIZE,
72679697Snon			sp->scp_direction, &stat);
72773149Snyan	}
72873149Snyan	else
72979697Snon	{
73073149Snyan		len = ct_xfer(ct, sp->scp_data, sp->scp_datalen,
73179697Snon			      sp->scp_direction, &stat);
73279697Snon		sp->scp_data += (sp->scp_datalen - len);
73379697Snon		sp->scp_datalen = len;
73479697Snon	}
73573149Snyan}
73673149Snyan
73773149Snyan/**************************************************
73873149Snyan * <PHASE ERROR>
73973149Snyan **************************************************/
74073149Snyanstruct ct_err {
74173149Snyan	u_char	*pe_msg;
74273149Snyan	u_int	pe_err;
74373149Snyan	u_int	pe_errmsg;
74473149Snyan	int	pe_done;
74573149Snyan};
74673149Snyan
74773149Snyanstruct ct_err ct_cmderr[] = {
74873149Snyan/*0*/	{ "illegal cmd", FATALIO, SCSI_LOW_MSG_ABORT, 1},
74973149Snyan/*1*/	{ "unexpected bus free", FATALIO, 0, 1},
75073149Snyan/*2*/	{ NULL, SELTIMEOUTIO, 0, 1},
75173149Snyan/*3*/	{ "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0},
75273149Snyan/*4*/	{ "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0},
75373149Snyan/*5*/	{ "unknown" , FATALIO, SCSI_LOW_MSG_ABORT, 1},
75473149Snyan/*6*/	{ "miss reselection (target mode)", FATALIO, SCSI_LOW_MSG_ABORT, 0},
75573149Snyan/*7*/	{ "wrong status byte", PARITYERR, SCSI_LOW_MSG_ERROR, 0},
75673149Snyan};
75773149Snyan
75873149Snyanstatic void
75973149Snyanct_phase_error(ct, scsi_status)
76073149Snyan	struct ct_softc *ct;
76173149Snyan	u_int8_t scsi_status;
76273149Snyan{
76373149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
76479697Snon	struct targ_info *ti = slp->sl_Tnexus;
76573149Snyan	struct ct_err *pep;
76673149Snyan	u_int msg = 0;
76773149Snyan
76873149Snyan	if ((scsi_status & BSR_CM) == BSR_CMDERR &&
76973149Snyan	    (scsi_status & BSR_PHVALID) == 0)
77073149Snyan	{
77173149Snyan		pep = &ct_cmderr[scsi_status & BSR_PM];
77273149Snyan		slp->sl_error |= pep->pe_err;
77373149Snyan		if ((pep->pe_err & PARITYERR) != 0)
77473149Snyan		{
77573149Snyan			if (ti->ti_phase == PH_MSGIN)
77673149Snyan				msg = SCSI_LOW_MSG_PARITY;
77773149Snyan			else
77873149Snyan				msg = SCSI_LOW_MSG_ERROR;
77973149Snyan		}
78073149Snyan		else
78173149Snyan			msg = pep->pe_errmsg;
78273149Snyan
78373149Snyan		if (msg != 0)
78479697Snon			scsi_low_assert_msg(slp, slp->sl_Tnexus, msg, 1);
78573149Snyan
78673149Snyan		if (pep->pe_msg != NULL)
78773149Snyan		{
78873149Snyan			printf("%s: phase error: %s",
78973149Snyan				slp->sl_xname, pep->pe_msg);
79079697Snon			scsi_low_print(slp, slp->sl_Tnexus);
79173149Snyan		}
79273149Snyan
79373149Snyan		if (pep->pe_done != 0)
79473149Snyan			scsi_low_disconnected(slp, ti);
79573149Snyan	}
79673149Snyan	else
79773149Snyan	{
79873149Snyan		slp->sl_error |= FATALIO;
79973149Snyan		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "phase error");
80073149Snyan	}
80173149Snyan}
80273149Snyan
80373149Snyan/**************************************************
80473149Snyan * ### SCSI PHASE SEQUENCER ###
80573149Snyan **************************************************/
80679697Snonstatic int
80779697Snonct_reselected(ct, scsi_status)
80873149Snyan	struct ct_softc *ct;
80979697Snon	u_int8_t scsi_status;
81073149Snyan{
81173149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
81279697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
81373149Snyan	struct targ_info *ti;
81473149Snyan	u_int sid;
81579697Snon	u_int8_t regv;
81673149Snyan
81773149Snyan	ct->sc_atten = 0;
81879697Snon	ct->sc_satgo &= ~CT_SAT_GOING;
81979697Snon	regv = ct_cr_read_1(chp, wd3s_sid);
82079697Snon	if ((regv & SIDR_VALID) == 0)
82179697Snon		return EJUSTRETURN;
82279697Snon
82379697Snon	sid = regv & SIDR_IDM;
82473149Snyan	if ((ti = scsi_low_reselected(slp, sid)) == NULL)
82573149Snyan		return EJUSTRETURN;
82673149Snyan
82779697Snon	ct_target_nexus_establish(ct, 0, SCSI_LOW_READ);
82879697Snon	if (scsi_status != BSR_AFM_RESEL)
82979697Snon		return EJUSTRETURN;
83079697Snon
83179697Snon	SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
83279697Snon	regv = ct_cr_read_1(chp, wd3s_data);
83379697Snon	if (scsi_low_msgin(slp, ti, (u_int) regv) == 0)
83479697Snon	{
83579697Snon		if (scsi_low_is_msgout_continue(ti, 0) != 0)
83679697Snon		{
83779697Snon			/* XXX: scsi_low_attetion */
83879697Snon			scsi_low_attention(slp);
83979697Snon		}
84079697Snon	}
84179697Snon
84279697Snon	if (ct->sc_atten != 0)
84379697Snon	{
84479697Snon		ct_attention(ct);
84579697Snon	}
84679697Snon
84779697Snon	ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK);
84873149Snyan	return EJUSTRETURN;
84973149Snyan}
85073149Snyan
85173149Snyanstatic int
85279697Snonct_target_nexus_establish(ct, lun, dir)
85373149Snyan	struct ct_softc *ct;
85479697Snon	int lun, dir;
85573149Snyan{
85679697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
85779697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
85879697Snon	struct targ_info *ti = slp->sl_Tnexus;
85973149Snyan	struct ct_targ_info *cti = (void *) ti;
86073149Snyan
86179697Snon	if (dir == SCSI_LOW_WRITE)
86279697Snon		ct_cr_write_1(chp, wd3s_did, ti->ti_id);
86373149Snyan	else
86479697Snon		ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD);
86579697Snon	ct_cr_write_1(chp, wd3s_lun, lun);
86679697Snon	ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA);
86779697Snon	ct_cr_write_1(chp, wd3s_cph, 0);
86879697Snon	ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg);
86979697Snon	cthw_set_count(chp, 0);
87079697Snon	return 0;
87179697Snon}
87273149Snyan
87379697Snonstatic int
87479697Snonct_lun_nexus_establish(ct)
87579697Snon	struct ct_softc *ct;
87679697Snon{
87779697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
87879697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
87979697Snon	struct lun_info *li = slp->sl_Lnexus;
88079697Snon
88179697Snon	ct_cr_write_1(chp, wd3s_lun, li->li_lun);
88273149Snyan	return 0;
88373149Snyan}
88473149Snyan
88579697Snonstatic int
88679697Snonct_ccb_nexus_establish(ct)
88779697Snon	struct ct_softc *ct;
88879697Snon{
88979697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
89079697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
89179697Snon	struct lun_info *li = slp->sl_Lnexus;
89279697Snon	struct targ_info *ti = slp->sl_Tnexus;
89379697Snon	struct ct_targ_info *cti = (void *) ti;
89479697Snon	struct slccb *cb = slp->sl_Qnexus;
89579697Snon
89679697Snon	ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
89779697Snon
89879697Snon	if ((ct->sc_satgo & CT_SAT_GOING) != 0)
89979697Snon	{
90079697Snon		ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen);
90179697Snon		ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
90279697Snon	}
90379697Snon	if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
90479697Snon		ct_cr_write_1(chp, wd3s_did, ti->ti_id);
90579697Snon	else
90679697Snon		ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD);
90779697Snon	ct_cr_write_1(chp, wd3s_lun, li->li_lun);
90879697Snon	ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg);
90979697Snon	return 0;
91079697Snon}
91179697Snon
91279697Snonstatic int
91379697Snonct_unbusy(ct)
91479697Snon	struct ct_softc *ct;
91579697Snon{
91679697Snon	struct scsi_low_softc *slp = &ct->sc_sclow;
91779697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
91879697Snon	int wc;
91979697Snon	register u_int8_t regv;
92079697Snon
92179697Snon	for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++)
92279697Snon	{
92379697Snon		regv = ct_stat_read_1(chp);
92479697Snon		if ((regv & (STR_BSY | STR_CIP)) == 0)
92579697Snon			return 0;
92679697Snon		if (regv == (u_int8_t) -1)
92779697Snon			return EIO;
92879697Snon
92979697Snon		SCSI_LOW_DELAY(CT_DELAY_INTERVAL);
93079697Snon	}
93179697Snon
93279697Snon	printf("%s: unbusy timeout\n", slp->sl_xname);
93379697Snon	return EBUSY;
93479697Snon}
93579697Snon
93679697Snonstatic int
93779697Snonct_catch_intr(ct)
93879697Snon	struct ct_softc *ct;
93979697Snon{
94079697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
94179697Snon	int wc;
94279697Snon	register u_int8_t regv;
94379697Snon
94479697Snon	for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++)
94579697Snon	{
94679697Snon		regv = ct_stat_read_1(chp);
94779697Snon		if ((regv & (STR_INT | STR_BSY | STR_CIP)) == STR_INT)
94879697Snon			return 0;
94979697Snon
95079697Snon		SCSI_LOW_DELAY(CT_DELAY_INTERVAL);
95179697Snon	}
95279697Snon	return EJUSTRETURN;
95379697Snon}
95479697Snon
95573149Snyanint
95673149Snyanctintr(arg)
95773149Snyan	void *arg;
95873149Snyan{
95973149Snyan	struct ct_softc *ct = arg;
96073149Snyan	struct scsi_low_softc *slp = &ct->sc_sclow;
96179697Snon	struct ct_bus_access_handle *chp = &ct->sc_ch;
96273149Snyan	struct targ_info *ti;
96373149Snyan	struct physio_proc *pp;
96473149Snyan	struct buf *bp;
96579697Snon	u_int derror, flags;
96679697Snon	int len, satgo, error;
96773149Snyan	u_int8_t scsi_status, regv;
96873149Snyan
96979697Snonagain:
97073149Snyan	if (slp->sl_flags & HW_INACTIVE)
97173149Snyan		return 0;
97273149Snyan
97373149Snyan	/**************************************************
97473149Snyan	 * Get status & bus phase
97573149Snyan	 **************************************************/
97679697Snon	if ((ct_stat_read_1(chp) & STR_INT) == 0)
97773149Snyan		return 0;
97873149Snyan
97979697Snon	scsi_status = ct_cr_read_1(chp, wd3s_stat);
98073149Snyan	if (scsi_status == ((u_int8_t) -1))
98173149Snyan		return 1;
98273149Snyan
98373149Snyan	/**************************************************
98473149Snyan	 * Check reselection, or nexus
98573149Snyan	 **************************************************/
98679697Snon	if (scsi_status == BSR_RESEL || scsi_status == BSR_AFM_RESEL)
98773149Snyan	{
98879697Snon		if (ct_reselected(ct, scsi_status) == EJUSTRETURN)
98973149Snyan			return 1;
99073149Snyan	}
99173149Snyan
99279697Snon	if ((ti = slp->sl_Tnexus) == NULL)
99373149Snyan		return 1;
99473149Snyan
99573149Snyan	/**************************************************
99673149Snyan	 * Debug section
99773149Snyan	 **************************************************/
99873149Snyan#ifdef	CT_DEBUG
99973149Snyan	if (ct_debug > 0)
100073149Snyan	{
100173149Snyan		scsi_low_print(slp, NULL);
100273149Snyan		printf("%s: scsi_status 0x%x\n\n", slp->sl_xname,
100373149Snyan		       (u_int) scsi_status);
100479697Snon#ifdef	DDB
100573149Snyan		if (ct_debug > 1)
100679697Snon			SCSI_LOW_DEBUGGER("ct");
100779697Snon#endif	/* DDB */
100873149Snyan	}
100973149Snyan#endif	/* CT_DEBUG */
101073149Snyan
101173149Snyan	/**************************************************
101273149Snyan	 * Internal scsi phase
101373149Snyan	 **************************************************/
101473149Snyan	satgo = ct->sc_satgo;
101579697Snon	ct->sc_satgo &= ~CT_SAT_GOING;
101673149Snyan
101773149Snyan	switch (ti->ti_phase)
101873149Snyan	{
101973149Snyan	case PH_SELSTART:
102073149Snyan		if ((satgo & CT_SAT_GOING) == 0)
102173149Snyan		{
102273149Snyan			if (scsi_status != BSR_SELECTED)
102373149Snyan			{
102473149Snyan				ct_phase_error(ct, scsi_status);
102573149Snyan				return 1;
102673149Snyan			}
102779697Snon			scsi_low_arbit_win(slp);
102873149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
102973149Snyan			return 1;
103073149Snyan		}
103173149Snyan		else
103273149Snyan		{
103379697Snon			scsi_low_arbit_win(slp);
103479697Snon			SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); /* XXX */
103573149Snyan		}
103673149Snyan		break;
103773149Snyan
103873149Snyan	case PH_RESEL:
103973149Snyan	    	if ((scsi_status & BSR_PHVALID) == 0 ||
104073149Snyan		    (scsi_status & BSR_PM) != BSR_MSGIN)
104173149Snyan		{
104273149Snyan			scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
104373149Snyan				 "phase miss after reselect");
104473149Snyan			return 1;
104573149Snyan		}
104673149Snyan		break;
104773149Snyan
104873149Snyan	default:
104973149Snyan		if (slp->sl_flags & HW_PDMASTART)
105073149Snyan		{
105173149Snyan			slp->sl_flags &= ~HW_PDMASTART;
105273149Snyan			if (ct->sc_dma & CT_DMA_DMASTART)
105373149Snyan			{
105473149Snyan				(*ct->ct_dma_xfer_stop) (ct);
105573149Snyan				ct->sc_dma &= ~CT_DMA_DMASTART;
105673149Snyan			}
105779697Snon			else if (ct->sc_dma & CT_DMA_PIOSTART)
105873149Snyan			{
105973149Snyan				(*ct->ct_pio_xfer_stop) (ct);
106073149Snyan				ct->sc_dma &= ~CT_DMA_PIOSTART;
106173149Snyan			}
106279697Snon			else
106379697Snon			{
106479697Snon				scsi_low_data_finish(slp);
106579697Snon			}
106673149Snyan		}
106773149Snyan		break;
106873149Snyan	}
106973149Snyan
107073149Snyan	/**************************************************
107173149Snyan	 * parse scsi phase
107273149Snyan	 **************************************************/
107373149Snyan	if (scsi_status & BSR_PHVALID)
107473149Snyan	{
107573149Snyan		/**************************************************
107673149Snyan		 * Normal SCSI phase.
107773149Snyan		 **************************************************/
107873149Snyan		if ((scsi_status & BSR_CM) == BSR_CMDABT)
107973149Snyan		{
108073149Snyan			ct_phase_error(ct, scsi_status);
108173149Snyan			return 1;
108273149Snyan		}
108373149Snyan
108473149Snyan		switch (scsi_status & BSR_PM)
108573149Snyan		{
108673149Snyan		case BSR_DATAOUT:
108773149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
108873149Snyan			if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
108979697Snon			{
109079697Snon				ct_attention(ct);
109179697Snon			}
109273149Snyan			goto common_data_phase;
109373149Snyan
109473149Snyan		case BSR_DATAIN:
109573149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
109673149Snyan			if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
109779697Snon			{
109879697Snon				ct_attention(ct);
109979697Snon			}
110073149Snyan
110173149Snyancommon_data_phase:
110279697Snon			if (slp->sl_scp.scp_datalen > 0)
110373149Snyan			{
110479697Snon				slp->sl_flags |= HW_PDMASTART;
110579697Snon				if ((ct->sc_xmode & CT_XMODE_PIO) != 0)
110679697Snon				{
110779697Snon					pp = physio_proc_enter(bp);
110879697Snon					error = (*ct->ct_pio_xfer_start) (ct);
110979697Snon					physio_proc_leave(pp);
111079697Snon					if (error == 0)
111179697Snon					{
111279697Snon						ct->sc_dma |= CT_DMA_PIOSTART;
111379697Snon						return 1;
111479697Snon					}
111579697Snon				}
111673149Snyan
111779697Snon				if ((ct->sc_xmode & CT_XMODE_DMA) != 0)
111879697Snon				{
111979697Snon					error = (*ct->ct_dma_xfer_start) (ct);
112079697Snon					if (error == 0)
112179697Snon					{
112279697Snon						ct->sc_dma |= CT_DMA_DMASTART;
112379697Snon						return 1;
112479697Snon					}
112579697Snon				}
112673149Snyan			}
112773149Snyan			else
112879697Snon			{
112979697Snon				if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
113079697Snon				{
113179697Snon					if (!(slp->sl_flags & HW_READ_PADDING))
113279697Snon					{
113379697Snon						printf("%s: read padding required\n", slp->sl_xname);
113479697Snon						return 1;
113579697Snon					}
113679697Snon				}
113779697Snon				else
113879697Snon				{
113979697Snon					if (!(slp->sl_flags & HW_WRITE_PADDING))
114079697Snon					{
114179697Snon						printf("%s: write padding required\n", slp->sl_xname);
114279697Snon						return 1;
114379697Snon					}
114479697Snon				}
114579697Snon				slp->sl_flags |= HW_PDMASTART;
114673149Snyan			}
114779697Snon
114879697Snon			ct_io_xfer(ct);
114973149Snyan			return 1;
115073149Snyan
115173149Snyan		case BSR_CMDOUT:
115273149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
115373149Snyan			if (scsi_low_cmd(slp, ti) != 0)
115479697Snon			{
115579697Snon				ct_attention(ct);
115679697Snon			}
115773149Snyan
115879697Snon			if (ct_xfer(ct, slp->sl_scp.scp_cmd,
115973149Snyan				    slp->sl_scp.scp_cmdlen,
116079697Snon				    SCSI_LOW_WRITE, &derror) != 0)
116173149Snyan			{
116273149Snyan				printf("%s: scsi cmd xfer short\n",
116373149Snyan					slp->sl_xname);
116473149Snyan			}
116573149Snyan			return 1;
116673149Snyan
116773149Snyan		case BSR_STATIN:
116873149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
116979697Snon			if ((ct_io_control & CT_USE_CCSEQ) != 0)
117073149Snyan			{
117179697Snon				if (scsi_low_is_msgout_continue(ti, 0) != 0 ||
117279697Snon				    ct->sc_atten != 0)
117379697Snon				{
117479697Snon					ct_xfer(ct, &regv, 1, SCSI_LOW_READ,
117579697Snon						&derror);
117679697Snon					scsi_low_statusin(slp, ti,
117779697Snon						  	  regv | derror);
117879697Snon				}
117979697Snon				else
118079697Snon				{
118179697Snon					ct->sc_satgo |= CT_SAT_GOING;
118279697Snon					cthw_set_count(chp, 0);
118379697Snon					cthw_phase_bypass(ct, 0x41);
118479697Snon				}
118573149Snyan			}
118673149Snyan			else
118773149Snyan			{
118879697Snon				ct_xfer(ct, &regv, 1, SCSI_LOW_READ, &derror);
118979697Snon				scsi_low_statusin(slp, ti, regv | derror);
119073149Snyan			}
119173149Snyan			return 1;
119273149Snyan
119373149Snyan		case BSR_UNSPINFO0:
119473149Snyan		case BSR_UNSPINFO1:
119573149Snyan			printf("%s: illegal bus phase (0x%x)\n", slp->sl_xname,
119673149Snyan				(u_int) scsi_status);
119773149Snyan			scsi_low_print(slp, ti);
119873149Snyan			return 1;
119973149Snyan
120073149Snyan		case BSR_MSGOUT:
120173149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
120279697Snon			flags = SCSI_LOW_MSGOUT_UNIFY;
120379697Snon		        if (ti->ti_ophase != ti->ti_phase)
120479697Snon				flags |= SCSI_LOW_MSGOUT_INIT;
120579697Snon			len = scsi_low_msgout(slp, ti, flags);
120679697Snon
120779697Snon			if (len > 1 && slp->sl_atten == 0)
120873149Snyan			{
120979697Snon				ct_attention(ct);
121079697Snon			}
121179697Snon
121279697Snon			if (ct_xfer(ct, ti->ti_msgoutstr, len,
121379697Snon				    SCSI_LOW_WRITE, &derror) != 0)
121479697Snon			{
121573149Snyan				printf("%s: scsi msgout xfer short\n",
121673149Snyan					slp->sl_xname);
121773149Snyan			}
121879697Snon			SCSI_LOW_DEASSERT_ATN(slp);
121979697Snon			ct->sc_atten = 0;
122073149Snyan			return 1;
122173149Snyan
122273149Snyan		case BSR_MSGIN:/* msg in */
122373149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
122479697Snon
122579697Snon			ct_xfer(ct, &regv, 1, SCSI_LOW_READ, &derror);
122679697Snon			if (scsi_low_msgin(slp, ti, regv | derror) == 0)
122779697Snon			{
122879697Snon				if (scsi_low_is_msgout_continue(ti, 0) != 0)
122979697Snon				{
123079697Snon					/* XXX: scsi_low_attetion */
123179697Snon					scsi_low_attention(slp);
123279697Snon				}
123379697Snon			}
123479697Snon
123579697Snon			if ((ct_io_control & CT_FAST_INTR) != 0)
123679697Snon			{
123779697Snon				if (ct_catch_intr(ct) == 0)
123879697Snon					goto again;
123979697Snon			}
124073149Snyan			return 1;
124173149Snyan		}
124273149Snyan	}
124373149Snyan	else
124473149Snyan	{
124573149Snyan		/**************************************************
124673149Snyan		 * Special SCSI phase
124773149Snyan		 **************************************************/
124873149Snyan		switch (scsi_status)
124973149Snyan		{
125073149Snyan		case BSR_SATSDP: /* SAT with save data pointer */
125173149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
125279697Snon			ct->sc_satgo |= CT_SAT_GOING;
125373149Snyan			scsi_low_msgin(slp, ti, MSG_SAVESP);
125473149Snyan			cthw_phase_bypass(ct, 0x41);
125573149Snyan			return 1;
125673149Snyan
125773149Snyan		case BSR_SATFIN: /* SAT COMPLETE */
125873149Snyan			/*
125973149Snyan			 * emulate statusin => msgin
126073149Snyan			 */
126179697Snon			SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
126279697Snon			scsi_low_statusin(slp, ti, ct_cr_read_1(chp, wd3s_lun));
126379697Snon
126473149Snyan			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
126579697Snon			scsi_low_msgin(slp, ti, MSG_COMP);
126679697Snon
126773149Snyan			scsi_low_disconnected(slp, ti);
126873149Snyan			return 1;
126973149Snyan
127073149Snyan		case BSR_ACKREQ: /* negate ACK */
127173149Snyan			if (ct->sc_atten != 0)
127279697Snon			{
127379697Snon				ct_attention(ct);
127479697Snon			}
127573149Snyan
127679697Snon			ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK);
127779697Snon			if ((ct_io_control & CT_FAST_INTR) != 0)
127879697Snon			{
127979697Snon				/* XXX:
128079697Snon				 * Should clear a pending interrupt and
128179697Snon				 * sync with a next interrupt!
128279697Snon				 */
128379697Snon				ct_catch_intr(ct);
128479697Snon			}
128573149Snyan			return 1;
128673149Snyan
128773149Snyan		case BSR_DISC: /* disconnect */
128873149Snyan			if (slp->sl_msgphase == MSGPH_NULL &&
128973149Snyan			    (satgo & CT_SAT_GOING) != 0)
129073149Snyan			{
129173149Snyan				/*
129273149Snyan				 * emulate disconnect msg
129373149Snyan				 */
129473149Snyan				SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
129579697Snon				scsi_low_msgin(slp, ti, MSG_DISCON);
129673149Snyan			}
129773149Snyan			scsi_low_disconnected(slp, ti);
129873149Snyan			return 1;
129973149Snyan
130073149Snyan		default:
130173149Snyan			break;
130273149Snyan		}
130373149Snyan	}
130473149Snyan
130573149Snyan	ct_phase_error(ct, scsi_status);
130673149Snyan	return 1;
130773149Snyan}
1308