xref: /inferno-os/os/boot/pc/sd53c8xx.c (revision 8a8c2d742b51525f66c2210e3c8a251de10022ff)
174a4d8c2SCharles.Forsyth /*
274a4d8c2SCharles.Forsyth  * NCR 53c8xx driver for Plan 9
374a4d8c2SCharles.Forsyth  * Nigel Roles (ngr@cotswold.demon.co.uk)
474a4d8c2SCharles.Forsyth  *
574a4d8c2SCharles.Forsyth  * 08/07/99	Ultra2 fixed. Brazil #ifdefs added. Fixed script error 6 diagnostics.
674a4d8c2SCharles.Forsyth  *
774a4d8c2SCharles.Forsyth  * 09/06/99	Enhancements to support 895 and 896 correctly. Attempt at Ultra 2 negotiation,
874a4d8c2SCharles.Forsyth  *		though no device to test with yet.
974a4d8c2SCharles.Forsyth  *		Variant now contains the number of valid chip registers to assist
1074a4d8c2SCharles.Forsyth  *		dumpncrregs()
1174a4d8c2SCharles.Forsyth  *
1274a4d8c2SCharles.Forsyth  * 06/10/98	Various bug fixes and Brazil compiler inspired changes from jmk
1374a4d8c2SCharles.Forsyth  *
1474a4d8c2SCharles.Forsyth  * 05/10/98	Small fix to handle command length being greater than expected by device
1574a4d8c2SCharles.Forsyth  *
1674a4d8c2SCharles.Forsyth  * 04/08/98     Added missing locks to interrupt handler. Marked places where
1774a4d8c2SCharles.Forsyth  *		multiple controller extensions could go
1874a4d8c2SCharles.Forsyth  *
1974a4d8c2SCharles.Forsyth  * 18/05/97	Fixed overestimate in size of local SCRIPT RAM
2074a4d8c2SCharles.Forsyth  *
2174a4d8c2SCharles.Forsyth  * 17/05/97	Bug fix to return status
2274a4d8c2SCharles.Forsyth  *
2374a4d8c2SCharles.Forsyth  * 06/10/96	Enhanced list of chip IDs. 875 revision 1 has no clock doubler, so assume it
2474a4d8c2SCharles.Forsyth  *		is shipped with 80MHz crystal. Use bit 3 of the GPREG to recognise differential
2574a4d8c2SCharles.Forsyth  *		boards. This is Symbios specific, but since they are about the only suppliers of
2674a4d8c2SCharles.Forsyth  *		differential cards.
2774a4d8c2SCharles.Forsyth  *
2874a4d8c2SCharles.Forsyth  * 23/9/96	Wide and Ultra supported. 825A and 860 added to variants. Dual compiling
2974a4d8c2SCharles.Forsyth  *		version for fileserver and cpu. 80MHz default clock for 860
3074a4d8c2SCharles.Forsyth  *
3174a4d8c2SCharles.Forsyth  * 5/8/96	Waits for an Inquiry message before initiating synchronous negotiation
3274a4d8c2SCharles.Forsyth  *		in case capabilities byte [7] indicates device does not support it. Devices
3374a4d8c2SCharles.Forsyth  *		which do target initiated negotiation will typically get in first; a few
3474a4d8c2SCharles.Forsyth  *		bugs in handling this have been fixed
3574a4d8c2SCharles.Forsyth  *
3674a4d8c2SCharles.Forsyth  * 3/8/96	Added differential support (put scsi0=diff in plan9.ini)
3774a4d8c2SCharles.Forsyth  *		Split exec() into exec() and io(). Exec() is small, and Io() does not
3874a4d8c2SCharles.Forsyth  *		use any Plan 9 specific data structures, so alternate exec() functions
3974a4d8c2SCharles.Forsyth  *		may be done for other environments, such as the fileserver
4074a4d8c2SCharles.Forsyth  *
4174a4d8c2SCharles.Forsyth  * GENERAL
4274a4d8c2SCharles.Forsyth  *
4374a4d8c2SCharles.Forsyth  * Works on 810 and 875
4474a4d8c2SCharles.Forsyth  * Should work on 815, 825, 810A, 825A, 860A
4574a4d8c2SCharles.Forsyth  * Uses local RAM, large FIFO, prefetch, burst opcode fetch, and 16 byte synch. offset
4674a4d8c2SCharles.Forsyth  * where applicable
4774a4d8c2SCharles.Forsyth  * Supports multi-target, wide, Ultra
4874a4d8c2SCharles.Forsyth  * Differential mode can be enabled by putting scsi0=diff in plan9.ini
4974a4d8c2SCharles.Forsyth  * NO SUPPORT FOR tagged queuing (yet)
5074a4d8c2SCharles.Forsyth  *
5174a4d8c2SCharles.Forsyth  * Known problems
5274a4d8c2SCharles.Forsyth  */
5374a4d8c2SCharles.Forsyth 
5474a4d8c2SCharles.Forsyth #define MAXTARGET	16		/* can be 8 or 16 */
5574a4d8c2SCharles.Forsyth 
5674a4d8c2SCharles.Forsyth #include "u.h"
5774a4d8c2SCharles.Forsyth #include "lib.h"
5874a4d8c2SCharles.Forsyth #include "mem.h"
5974a4d8c2SCharles.Forsyth #include "dat.h"
6074a4d8c2SCharles.Forsyth #include "fns.h"
6174a4d8c2SCharles.Forsyth #include "io.h"
6274a4d8c2SCharles.Forsyth #include "ureg.h"
6374a4d8c2SCharles.Forsyth #include "error.h"
6474a4d8c2SCharles.Forsyth 
6574a4d8c2SCharles.Forsyth #include "sd.h"
6674a4d8c2SCharles.Forsyth extern SDifc sd53c8xxifc;
6774a4d8c2SCharles.Forsyth 
6874a4d8c2SCharles.Forsyth #define waserror()	(0)
6974a4d8c2SCharles.Forsyth #define poperror()
7074a4d8c2SCharles.Forsyth typedef struct QLock{ int r; } QLock;
7174a4d8c2SCharles.Forsyth typedef struct Rendez{ int r; } Rendez;
7274a4d8c2SCharles.Forsyth #define	intrenable(irq, f, c, tbdf, name)	setvec(VectorPIC+(irq), f, c);
7374a4d8c2SCharles.Forsyth 
7474a4d8c2SCharles.Forsyth /**********************************/
7574a4d8c2SCharles.Forsyth /* Portable configuration macros  */
7674a4d8c2SCharles.Forsyth /**********************************/
7774a4d8c2SCharles.Forsyth 
7874a4d8c2SCharles.Forsyth //#define BOOTDEBUG
7974a4d8c2SCharles.Forsyth //#define ASYNC_ONLY
8074a4d8c2SCharles.Forsyth //#define	INTERNAL_SCLK
8174a4d8c2SCharles.Forsyth //#define ALWAYS_DO_WDTR
8274a4d8c2SCharles.Forsyth #define WMR_DEBUG
8374a4d8c2SCharles.Forsyth 
8474a4d8c2SCharles.Forsyth /**********************************/
8574a4d8c2SCharles.Forsyth /* CPU specific macros            */
8674a4d8c2SCharles.Forsyth /**********************************/
8774a4d8c2SCharles.Forsyth 
8874a4d8c2SCharles.Forsyth #ifdef BOOTDEBUG
8974a4d8c2SCharles.Forsyth 
9074a4d8c2SCharles.Forsyth #define KPRINT oprint
9174a4d8c2SCharles.Forsyth #define IPRINT intrprint
9274a4d8c2SCharles.Forsyth #define DEBUG(n) 0
9374a4d8c2SCharles.Forsyth #define IFLUSH() iflush()
9474a4d8c2SCharles.Forsyth 
9574a4d8c2SCharles.Forsyth #else
9674a4d8c2SCharles.Forsyth 
9774a4d8c2SCharles.Forsyth #define KPRINT	if(0)print
9874a4d8c2SCharles.Forsyth #define IPRINT	if(0)print
9974a4d8c2SCharles.Forsyth #define DEBUG(n)	(0)
10074a4d8c2SCharles.Forsyth #define IFLUSH()
10174a4d8c2SCharles.Forsyth 
10274a4d8c2SCharles.Forsyth #endif /* BOOTDEBUG */
10374a4d8c2SCharles.Forsyth 
10474a4d8c2SCharles.Forsyth /*******************************/
10574a4d8c2SCharles.Forsyth /* General                     */
10674a4d8c2SCharles.Forsyth /*******************************/
10774a4d8c2SCharles.Forsyth 
10874a4d8c2SCharles.Forsyth #ifndef DMASEG
10974a4d8c2SCharles.Forsyth #define DMASEG(x) PADDR(x)
11074a4d8c2SCharles.Forsyth #define legetl(x) (*(ulong*)(x))
11174a4d8c2SCharles.Forsyth #define lesetl(x,v) (*(ulong*)(x) = (v))
11274a4d8c2SCharles.Forsyth #define swabl(a,b,c)
11374a4d8c2SCharles.Forsyth #else
11474a4d8c2SCharles.Forsyth #endif /*DMASEG */
11574a4d8c2SCharles.Forsyth #define DMASEG_TO_KADDR(x) KADDR(PADDR(x))
11674a4d8c2SCharles.Forsyth #define KPTR(x) ((x) == 0 ? 0 : DMASEG_TO_KADDR(x))
11774a4d8c2SCharles.Forsyth 
11874a4d8c2SCharles.Forsyth #define MEGA 1000000L
11974a4d8c2SCharles.Forsyth #ifdef INTERNAL_SCLK
12074a4d8c2SCharles.Forsyth #define	SCLK (33 * MEGA)
12174a4d8c2SCharles.Forsyth #else
12274a4d8c2SCharles.Forsyth #define SCLK (40 * MEGA)
12374a4d8c2SCharles.Forsyth #endif /* INTERNAL_SCLK */
12474a4d8c2SCharles.Forsyth #define ULTRA_NOCLOCKDOUBLE_SCLK (80 * MEGA)
12574a4d8c2SCharles.Forsyth 
12674a4d8c2SCharles.Forsyth #define MAXSYNCSCSIRATE (5 * MEGA)
12774a4d8c2SCharles.Forsyth #define MAXFASTSYNCSCSIRATE (10 * MEGA)
12874a4d8c2SCharles.Forsyth #define MAXULTRASYNCSCSIRATE (20 * MEGA)
12974a4d8c2SCharles.Forsyth #define MAXULTRA2SYNCSCSIRATE (40 * MEGA)
13074a4d8c2SCharles.Forsyth #define MAXASYNCCORERATE (25 * MEGA)
13174a4d8c2SCharles.Forsyth #define MAXSYNCCORERATE (25 * MEGA)
13274a4d8c2SCharles.Forsyth #define MAXFASTSYNCCORERATE (50 * MEGA)
13374a4d8c2SCharles.Forsyth #define MAXULTRASYNCCORERATE (80 * MEGA)
13474a4d8c2SCharles.Forsyth #define MAXULTRA2SYNCCORERATE (160 * MEGA)
13574a4d8c2SCharles.Forsyth 
13674a4d8c2SCharles.Forsyth 
13774a4d8c2SCharles.Forsyth #define X_MSG	1
13874a4d8c2SCharles.Forsyth #define X_MSG_SDTR 1
13974a4d8c2SCharles.Forsyth #define X_MSG_WDTR 3
14074a4d8c2SCharles.Forsyth 
14174a4d8c2SCharles.Forsyth struct na_patch {
14274a4d8c2SCharles.Forsyth 	unsigned lwoff;
14374a4d8c2SCharles.Forsyth 	unsigned char type;
14474a4d8c2SCharles.Forsyth };
14574a4d8c2SCharles.Forsyth 
14674a4d8c2SCharles.Forsyth typedef struct Ncr {
14774a4d8c2SCharles.Forsyth 	uchar scntl0;	/* 00 */
14874a4d8c2SCharles.Forsyth 	uchar scntl1;
14974a4d8c2SCharles.Forsyth 	uchar scntl2;
15074a4d8c2SCharles.Forsyth 	uchar scntl3;
15174a4d8c2SCharles.Forsyth 
15274a4d8c2SCharles.Forsyth 	uchar scid;	/* 04 */
15374a4d8c2SCharles.Forsyth 	uchar sxfer;
15474a4d8c2SCharles.Forsyth 	uchar sdid;
15574a4d8c2SCharles.Forsyth 	uchar gpreg;
15674a4d8c2SCharles.Forsyth 
15774a4d8c2SCharles.Forsyth 	uchar sfbr;	/* 08 */
15874a4d8c2SCharles.Forsyth 	uchar socl;
15974a4d8c2SCharles.Forsyth 	uchar ssid;
16074a4d8c2SCharles.Forsyth 	uchar sbcl;
16174a4d8c2SCharles.Forsyth 
16274a4d8c2SCharles.Forsyth 	uchar dstat;	/* 0c */
16374a4d8c2SCharles.Forsyth 	uchar sstat0;
16474a4d8c2SCharles.Forsyth 	uchar sstat1;
16574a4d8c2SCharles.Forsyth 	uchar sstat2;
16674a4d8c2SCharles.Forsyth 
16774a4d8c2SCharles.Forsyth 	uchar dsa[4];	/* 10 */
16874a4d8c2SCharles.Forsyth 
16974a4d8c2SCharles.Forsyth 	uchar istat;	/* 14 */
17074a4d8c2SCharles.Forsyth 	uchar istatpad[3];
17174a4d8c2SCharles.Forsyth 
17274a4d8c2SCharles.Forsyth 	uchar ctest0;	/* 18 */
17374a4d8c2SCharles.Forsyth 	uchar ctest1;
17474a4d8c2SCharles.Forsyth 	uchar ctest2;
17574a4d8c2SCharles.Forsyth 	uchar ctest3;
17674a4d8c2SCharles.Forsyth 
17774a4d8c2SCharles.Forsyth 	uchar temp[4];	/* 1c */
17874a4d8c2SCharles.Forsyth 
17974a4d8c2SCharles.Forsyth 	uchar dfifo;	/* 20 */
18074a4d8c2SCharles.Forsyth 	uchar ctest4;
18174a4d8c2SCharles.Forsyth 	uchar ctest5;
18274a4d8c2SCharles.Forsyth 	uchar ctest6;
18374a4d8c2SCharles.Forsyth 
18474a4d8c2SCharles.Forsyth 	uchar dbc[3];	/* 24 */
18574a4d8c2SCharles.Forsyth 	uchar dcmd;	/* 27 */
18674a4d8c2SCharles.Forsyth 
18774a4d8c2SCharles.Forsyth 	uchar dnad[4];	/* 28 */
18874a4d8c2SCharles.Forsyth 	uchar dsp[4];	/* 2c */
18974a4d8c2SCharles.Forsyth 	uchar dsps[4];	/* 30 */
19074a4d8c2SCharles.Forsyth 
19174a4d8c2SCharles.Forsyth 	uchar scratcha[4];	/* 34 */
19274a4d8c2SCharles.Forsyth 
19374a4d8c2SCharles.Forsyth 	uchar dmode;	/* 38 */
19474a4d8c2SCharles.Forsyth 	uchar dien;
19574a4d8c2SCharles.Forsyth 	uchar dwt;
19674a4d8c2SCharles.Forsyth 	uchar dcntl;
19774a4d8c2SCharles.Forsyth 
19874a4d8c2SCharles.Forsyth 	uchar adder[4];	/* 3c */
19974a4d8c2SCharles.Forsyth 
20074a4d8c2SCharles.Forsyth 	uchar sien0;	/* 40 */
20174a4d8c2SCharles.Forsyth 	uchar sien1;
20274a4d8c2SCharles.Forsyth 	uchar sist0;
20374a4d8c2SCharles.Forsyth 	uchar sist1;
20474a4d8c2SCharles.Forsyth 
20574a4d8c2SCharles.Forsyth 	uchar slpar;	/* 44 */
20674a4d8c2SCharles.Forsyth 	uchar slparpad0;
20774a4d8c2SCharles.Forsyth 	uchar macntl;
20874a4d8c2SCharles.Forsyth 	uchar gpcntl;
20974a4d8c2SCharles.Forsyth 
21074a4d8c2SCharles.Forsyth 	uchar stime0;	/* 48 */
21174a4d8c2SCharles.Forsyth 	uchar stime1;
21274a4d8c2SCharles.Forsyth 	uchar respid;
21374a4d8c2SCharles.Forsyth 	uchar respidpad0;
21474a4d8c2SCharles.Forsyth 
21574a4d8c2SCharles.Forsyth 	uchar stest0;	/* 4c */
21674a4d8c2SCharles.Forsyth 	uchar stest1;
21774a4d8c2SCharles.Forsyth 	uchar stest2;
21874a4d8c2SCharles.Forsyth 	uchar stest3;
21974a4d8c2SCharles.Forsyth 
22074a4d8c2SCharles.Forsyth 	uchar sidl;	/* 50 */
22174a4d8c2SCharles.Forsyth 	uchar sidlpad[3];
22274a4d8c2SCharles.Forsyth 
22374a4d8c2SCharles.Forsyth 	uchar sodl;	/* 54 */
22474a4d8c2SCharles.Forsyth 	uchar sodlpad[3];
22574a4d8c2SCharles.Forsyth 
22674a4d8c2SCharles.Forsyth 	uchar sbdl;	/* 58 */
22774a4d8c2SCharles.Forsyth 	uchar sbdlpad[3];
22874a4d8c2SCharles.Forsyth 
22974a4d8c2SCharles.Forsyth 	uchar scratchb[4];	/* 5c */
23074a4d8c2SCharles.Forsyth } Ncr;
23174a4d8c2SCharles.Forsyth 
23274a4d8c2SCharles.Forsyth typedef struct Movedata {
23374a4d8c2SCharles.Forsyth 	uchar dbc[4];
23474a4d8c2SCharles.Forsyth 	uchar pa[4];
23574a4d8c2SCharles.Forsyth } Movedata;
23674a4d8c2SCharles.Forsyth 
23774a4d8c2SCharles.Forsyth typedef enum NegoState {
23874a4d8c2SCharles.Forsyth 	NeitherDone, WideInit, WideResponse, WideDone,
23974a4d8c2SCharles.Forsyth 	SyncInit, SyncResponse, BothDone
24074a4d8c2SCharles.Forsyth } NegoState;
24174a4d8c2SCharles.Forsyth 
24274a4d8c2SCharles.Forsyth typedef enum State {
24374a4d8c2SCharles.Forsyth 	Allocated, Queued, Active, Done
24474a4d8c2SCharles.Forsyth } State;
24574a4d8c2SCharles.Forsyth 
24674a4d8c2SCharles.Forsyth typedef struct Dsa {
24774a4d8c2SCharles.Forsyth 	union {
24874a4d8c2SCharles.Forsyth 		uchar state[4];
24974a4d8c2SCharles.Forsyth 		struct {
25074a4d8c2SCharles.Forsyth 			uchar stateb;
25174a4d8c2SCharles.Forsyth 			uchar result;
25274a4d8c2SCharles.Forsyth 			uchar dmablks;
25374a4d8c2SCharles.Forsyth 			uchar flag;	/* setbyte(state,3,...) */
25474a4d8c2SCharles.Forsyth 		};
25574a4d8c2SCharles.Forsyth 	};
25674a4d8c2SCharles.Forsyth 
25774a4d8c2SCharles.Forsyth 	union {
25874a4d8c2SCharles.Forsyth 		ulong dmancr;		/* For block transfer: NCR order (little-endian) */
25974a4d8c2SCharles.Forsyth 		uchar dmaaddr[4];
26074a4d8c2SCharles.Forsyth 	};
26174a4d8c2SCharles.Forsyth 
26274a4d8c2SCharles.Forsyth 	uchar target;			/* Target */
26374a4d8c2SCharles.Forsyth 	uchar pad0[3];
26474a4d8c2SCharles.Forsyth 
26574a4d8c2SCharles.Forsyth 	uchar lun;			/* Logical Unit Number */
26674a4d8c2SCharles.Forsyth 	uchar pad1[3];
26774a4d8c2SCharles.Forsyth 
26874a4d8c2SCharles.Forsyth 	uchar scntl3;
26974a4d8c2SCharles.Forsyth 	uchar sxfer;
27074a4d8c2SCharles.Forsyth 	uchar pad2[2];
27174a4d8c2SCharles.Forsyth 
27274a4d8c2SCharles.Forsyth 	uchar next[4];			/* chaining for SCRIPT (NCR byte order) */
27374a4d8c2SCharles.Forsyth 	struct Dsa *freechain;		/* chaining for freelist */
27474a4d8c2SCharles.Forsyth 	Rendez;
27574a4d8c2SCharles.Forsyth 	uchar scsi_id_buf[4];
27674a4d8c2SCharles.Forsyth 	Movedata msg_out_buf;
27774a4d8c2SCharles.Forsyth 	Movedata cmd_buf;
27874a4d8c2SCharles.Forsyth 	Movedata data_buf;
27974a4d8c2SCharles.Forsyth 	Movedata status_buf;
28074a4d8c2SCharles.Forsyth 	uchar msg_out[10];		/* enough to include SDTR */
28174a4d8c2SCharles.Forsyth 	uchar status;
28274a4d8c2SCharles.Forsyth 	int p9status;
28374a4d8c2SCharles.Forsyth 	uchar parityerror;
28474a4d8c2SCharles.Forsyth } Dsa;
28574a4d8c2SCharles.Forsyth 
28674a4d8c2SCharles.Forsyth typedef enum Feature {
28774a4d8c2SCharles.Forsyth 	BigFifo = 1,			/* 536 byte fifo */
28874a4d8c2SCharles.Forsyth 	BurstOpCodeFetch = 2,		/* burst fetch opcodes */
28974a4d8c2SCharles.Forsyth 	Prefetch = 4,			/* prefetch 8 longwords */
29074a4d8c2SCharles.Forsyth 	LocalRAM = 8,			/* 4K longwords of local RAM */
29174a4d8c2SCharles.Forsyth 	Differential = 16,		/* Differential support */
29274a4d8c2SCharles.Forsyth 	Wide = 32,			/* Wide capable */
29374a4d8c2SCharles.Forsyth 	Ultra = 64,			/* Ultra capable */
29474a4d8c2SCharles.Forsyth 	ClockDouble = 128,		/* Has clock doubler */
29574a4d8c2SCharles.Forsyth 	ClockQuad = 256,		/* Has clock quadrupler (same as Ultra2) */
29674a4d8c2SCharles.Forsyth 	Ultra2 = 256,
29774a4d8c2SCharles.Forsyth } Feature;
29874a4d8c2SCharles.Forsyth 
29974a4d8c2SCharles.Forsyth typedef enum Burst {
30074a4d8c2SCharles.Forsyth 	Burst2 = 0,
30174a4d8c2SCharles.Forsyth 	Burst4 = 1,
30274a4d8c2SCharles.Forsyth 	Burst8 = 2,
30374a4d8c2SCharles.Forsyth 	Burst16 = 3,
30474a4d8c2SCharles.Forsyth 	Burst32 = 4,
30574a4d8c2SCharles.Forsyth 	Burst64 = 5,
30674a4d8c2SCharles.Forsyth 	Burst128 = 6
30774a4d8c2SCharles.Forsyth } Burst;
30874a4d8c2SCharles.Forsyth 
30974a4d8c2SCharles.Forsyth typedef struct Variant {
31074a4d8c2SCharles.Forsyth 	ushort did;
31174a4d8c2SCharles.Forsyth 	uchar maxrid;			/* maximum allowed revision ID */
31274a4d8c2SCharles.Forsyth 	char *name;
31374a4d8c2SCharles.Forsyth 	Burst burst;			/* codings for max burst */
31474a4d8c2SCharles.Forsyth 	uchar maxsyncoff;		/* max synchronous offset */
31574a4d8c2SCharles.Forsyth 	uchar registers;		/* number of 32 bit registers */
31674a4d8c2SCharles.Forsyth 	unsigned feature;
31774a4d8c2SCharles.Forsyth } Variant;
31874a4d8c2SCharles.Forsyth 
31974a4d8c2SCharles.Forsyth static unsigned char cf2[] = { 6, 2, 3, 4, 6, 8, 12, 16 };
32074a4d8c2SCharles.Forsyth #define NULTRA2SCF (sizeof(cf2)/sizeof(cf2[0]))
32174a4d8c2SCharles.Forsyth #define NULTRASCF (NULTRA2SCF - 2)
32274a4d8c2SCharles.Forsyth #define NSCF (NULTRASCF - 1)
32374a4d8c2SCharles.Forsyth 
32474a4d8c2SCharles.Forsyth typedef struct Controller {
32574a4d8c2SCharles.Forsyth 	Lock;
32674a4d8c2SCharles.Forsyth 	struct {
32774a4d8c2SCharles.Forsyth 		uchar scntl3;
32874a4d8c2SCharles.Forsyth 		uchar stest2;
32974a4d8c2SCharles.Forsyth 	} bios;
33074a4d8c2SCharles.Forsyth 	uchar synctab[NULTRA2SCF - 1][8];/* table of legal tpfs */
33174a4d8c2SCharles.Forsyth 	NegoState s[MAXTARGET];
33274a4d8c2SCharles.Forsyth 	uchar scntl3[MAXTARGET];
33374a4d8c2SCharles.Forsyth 	uchar sxfer[MAXTARGET];
33474a4d8c2SCharles.Forsyth 	uchar cap[MAXTARGET];		/* capabilities byte from Identify */
33574a4d8c2SCharles.Forsyth 	ushort capvalid;		/* bit per target for validity of cap[] */
33674a4d8c2SCharles.Forsyth 	ushort wide;			/* bit per target set if wide negotiated */
33774a4d8c2SCharles.Forsyth 	ulong sclk;			/* clock speed of controller */
33874a4d8c2SCharles.Forsyth 	uchar clockmult;		/* set by synctabinit */
33974a4d8c2SCharles.Forsyth 	uchar ccf;			/* CCF bits */
34074a4d8c2SCharles.Forsyth 	uchar tpf;			/* best tpf value for this controller */
34174a4d8c2SCharles.Forsyth 	uchar feature;			/* requested features */
34274a4d8c2SCharles.Forsyth 	int running;			/* is the script processor running? */
34374a4d8c2SCharles.Forsyth 	int ssm;			/* single step mode */
34474a4d8c2SCharles.Forsyth 	Ncr *n;				/* pointer to registers */
34574a4d8c2SCharles.Forsyth 	Variant *v;			/* pointer to variant type */
34674a4d8c2SCharles.Forsyth 	ulong *script;			/* where the real script is */
34774a4d8c2SCharles.Forsyth 	ulong scriptpa;			/* where the real script is */
34874a4d8c2SCharles.Forsyth 	Pcidev* pcidev;
34974a4d8c2SCharles.Forsyth 	SDev*	sdev;
35074a4d8c2SCharles.Forsyth 
35174a4d8c2SCharles.Forsyth 	struct {
35274a4d8c2SCharles.Forsyth 		Lock;
35374a4d8c2SCharles.Forsyth 		uchar head[4];		/* head of free list (NCR byte order) */
35474a4d8c2SCharles.Forsyth 		Dsa	*tail;
35574a4d8c2SCharles.Forsyth 		Dsa	*freechain;
35674a4d8c2SCharles.Forsyth 	} dsalist;
35774a4d8c2SCharles.Forsyth 
35874a4d8c2SCharles.Forsyth 	QLock q[MAXTARGET];		/* queues for each target */
35974a4d8c2SCharles.Forsyth } Controller;
36074a4d8c2SCharles.Forsyth 
36174a4d8c2SCharles.Forsyth static Controller controller;
36274a4d8c2SCharles.Forsyth 
36374a4d8c2SCharles.Forsyth /* ISTAT */
36474a4d8c2SCharles.Forsyth enum { Abrt = 0x80, Srst = 0x40, Sigp = 0x20, Sem = 0x10, Con = 0x08, Intf = 0x04, Sip = 0x02, Dip = 0x01 };
36574a4d8c2SCharles.Forsyth 
36674a4d8c2SCharles.Forsyth /* DSTAT */
36774a4d8c2SCharles.Forsyth enum { Dfe = 0x80, Mdpe = 0x40, Bf = 0x20, Abrted = 0x10, Ssi = 0x08, Sir = 0x04, Iid = 0x01 };
36874a4d8c2SCharles.Forsyth 
36974a4d8c2SCharles.Forsyth /* SSTAT */
37074a4d8c2SCharles.Forsyth enum { DataOut, DataIn, Cmd, Status, ReservedOut, ReservedIn, MessageOut, MessageIn };
37174a4d8c2SCharles.Forsyth 
37274a4d8c2SCharles.Forsyth static void setmovedata(Movedata*, ulong, ulong);
37374a4d8c2SCharles.Forsyth static void advancedata(Movedata*, long);
37474a4d8c2SCharles.Forsyth static int bios_set_differential(Controller *c);
37574a4d8c2SCharles.Forsyth 
37674a4d8c2SCharles.Forsyth static char *phase[] = {
37774a4d8c2SCharles.Forsyth 	"data out", "data in", "command", "status",
37874a4d8c2SCharles.Forsyth 	"reserved out", "reserved in", "message out", "message in"
37974a4d8c2SCharles.Forsyth };
38074a4d8c2SCharles.Forsyth 
38174a4d8c2SCharles.Forsyth #ifdef BOOTDEBUG
38274a4d8c2SCharles.Forsyth #define DEBUGSIZE 10240
38374a4d8c2SCharles.Forsyth char debugbuf[DEBUGSIZE];
38474a4d8c2SCharles.Forsyth char *debuglast;
38574a4d8c2SCharles.Forsyth 
38674a4d8c2SCharles.Forsyth static void
intrprint(char * format,...)38774a4d8c2SCharles.Forsyth intrprint(char *format, ...)
38874a4d8c2SCharles.Forsyth {
38974a4d8c2SCharles.Forsyth 	if (debuglast == 0)
39074a4d8c2SCharles.Forsyth 		debuglast = debugbuf;
39174a4d8c2SCharles.Forsyth 	debuglast = doprint(debuglast, debugbuf + (DEBUGSIZE - 1), format, (&format + 1));
39274a4d8c2SCharles.Forsyth }
39374a4d8c2SCharles.Forsyth 
39474a4d8c2SCharles.Forsyth static void
iflush()39574a4d8c2SCharles.Forsyth iflush()
39674a4d8c2SCharles.Forsyth {
39774a4d8c2SCharles.Forsyth 	int s;
39874a4d8c2SCharles.Forsyth 	char *endp;
39974a4d8c2SCharles.Forsyth 	s = splhi();
40074a4d8c2SCharles.Forsyth 	if (debuglast == 0)
40174a4d8c2SCharles.Forsyth 		debuglast = debugbuf;
40274a4d8c2SCharles.Forsyth 	if (debuglast == debugbuf) {
40374a4d8c2SCharles.Forsyth 		splx(s);
40474a4d8c2SCharles.Forsyth 		return;
40574a4d8c2SCharles.Forsyth 	}
40674a4d8c2SCharles.Forsyth 	endp = debuglast;
40774a4d8c2SCharles.Forsyth 	splx(s);
40874a4d8c2SCharles.Forsyth 	screenputs(debugbuf, endp - debugbuf);
40974a4d8c2SCharles.Forsyth 	s = splhi();
41074a4d8c2SCharles.Forsyth 	memmove(debugbuf, endp, debuglast - endp);
41174a4d8c2SCharles.Forsyth 	debuglast -= endp - debugbuf;
41274a4d8c2SCharles.Forsyth 	splx(s);
41374a4d8c2SCharles.Forsyth }
41474a4d8c2SCharles.Forsyth 
41574a4d8c2SCharles.Forsyth static void
oprint(char * format,...)41674a4d8c2SCharles.Forsyth oprint(char *format, ...)
41774a4d8c2SCharles.Forsyth {
41874a4d8c2SCharles.Forsyth 	int s;
41974a4d8c2SCharles.Forsyth 
42074a4d8c2SCharles.Forsyth 	iflush();
42174a4d8c2SCharles.Forsyth 	s = splhi();
42274a4d8c2SCharles.Forsyth 	if (debuglast == 0)
42374a4d8c2SCharles.Forsyth 		debuglast = debugbuf;
42474a4d8c2SCharles.Forsyth 	debuglast = doprint(debuglast, debugbuf + (DEBUGSIZE - 1), format, (&format + 1));
42574a4d8c2SCharles.Forsyth 	splx(s);
42674a4d8c2SCharles.Forsyth 	iflush();
42774a4d8c2SCharles.Forsyth }
42874a4d8c2SCharles.Forsyth #endif
42974a4d8c2SCharles.Forsyth 
43074a4d8c2SCharles.Forsyth #include "sd53c8xx.i"
43174a4d8c2SCharles.Forsyth 
43274a4d8c2SCharles.Forsyth static Dsa *
dsaalloc(Controller * c,int target,int lun)43374a4d8c2SCharles.Forsyth dsaalloc(Controller *c, int target, int lun)
43474a4d8c2SCharles.Forsyth {
43574a4d8c2SCharles.Forsyth 	Dsa *d;
43674a4d8c2SCharles.Forsyth 
43774a4d8c2SCharles.Forsyth 	ilock(&c->dsalist);
43874a4d8c2SCharles.Forsyth 	if ((d = c->dsalist.freechain) == 0) {
43974a4d8c2SCharles.Forsyth 		d = xalloc(sizeof(*d));
44074a4d8c2SCharles.Forsyth 		if (DEBUG(1))
44174a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d/%d: allocated new dsa %lux\n", target, lun, d);
44274a4d8c2SCharles.Forsyth 		lesetl(d->next, 0);
44374a4d8c2SCharles.Forsyth 		lesetl(d->state, A_STATE_ALLOCATED);
44474a4d8c2SCharles.Forsyth 		if (legetl(c->dsalist.head) == 0)
44574a4d8c2SCharles.Forsyth 			lesetl(c->dsalist.head, DMASEG(d));	/* ATOMIC?!? */
44674a4d8c2SCharles.Forsyth 		else
44774a4d8c2SCharles.Forsyth 			lesetl(c->dsalist.tail->next, DMASEG(d));	/* ATOMIC?!? */
44874a4d8c2SCharles.Forsyth 		c->dsalist.tail = d;
44974a4d8c2SCharles.Forsyth 	}
45074a4d8c2SCharles.Forsyth 	else {
45174a4d8c2SCharles.Forsyth 		if (DEBUG(1))
45274a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d/%d: reused dsa %lux\n", target, lun, d);
45374a4d8c2SCharles.Forsyth 		c->dsalist.freechain = d->freechain;
45474a4d8c2SCharles.Forsyth 		lesetl(d->state, A_STATE_ALLOCATED);
45574a4d8c2SCharles.Forsyth 	}
45674a4d8c2SCharles.Forsyth 	iunlock(&c->dsalist);
45774a4d8c2SCharles.Forsyth 	d->target = target;
45874a4d8c2SCharles.Forsyth 	d->lun = lun;
45974a4d8c2SCharles.Forsyth 	return d;
46074a4d8c2SCharles.Forsyth }
46174a4d8c2SCharles.Forsyth 
46274a4d8c2SCharles.Forsyth static void
dsafree(Controller * c,Dsa * d)46374a4d8c2SCharles.Forsyth dsafree(Controller *c, Dsa *d)
46474a4d8c2SCharles.Forsyth {
46574a4d8c2SCharles.Forsyth 	ilock(&c->dsalist);
46674a4d8c2SCharles.Forsyth 	d->freechain = c->dsalist.freechain;
46774a4d8c2SCharles.Forsyth 	c->dsalist.freechain = d;
46874a4d8c2SCharles.Forsyth 	lesetl(d->state, A_STATE_FREE);
46974a4d8c2SCharles.Forsyth 	iunlock(&c->dsalist);
47074a4d8c2SCharles.Forsyth }
47174a4d8c2SCharles.Forsyth 
47274a4d8c2SCharles.Forsyth static Dsa *
dsafind(Controller * c,uchar target,uchar lun,uchar state)47374a4d8c2SCharles.Forsyth dsafind(Controller *c, uchar target, uchar lun, uchar state)
47474a4d8c2SCharles.Forsyth {
47574a4d8c2SCharles.Forsyth 	Dsa *d;
47674a4d8c2SCharles.Forsyth 	for (d = KPTR(legetl(c->dsalist.head)); d; d = KPTR(legetl(d->next))) {
47774a4d8c2SCharles.Forsyth 		if (d->target != 0xff && d->target != target)
47874a4d8c2SCharles.Forsyth 			continue;
47974a4d8c2SCharles.Forsyth 		if (lun != 0xff && d->lun != lun)
48074a4d8c2SCharles.Forsyth 			continue;
48174a4d8c2SCharles.Forsyth 		if (state != 0xff && d->stateb != state)
48274a4d8c2SCharles.Forsyth 			continue;
48374a4d8c2SCharles.Forsyth 		break;
48474a4d8c2SCharles.Forsyth 	}
48574a4d8c2SCharles.Forsyth 	return d;
48674a4d8c2SCharles.Forsyth }
48774a4d8c2SCharles.Forsyth 
48874a4d8c2SCharles.Forsyth static void
dumpncrregs(Controller * c,int intr)48974a4d8c2SCharles.Forsyth dumpncrregs(Controller *c, int intr)
49074a4d8c2SCharles.Forsyth {
49174a4d8c2SCharles.Forsyth 	int i;
49274a4d8c2SCharles.Forsyth 	Ncr *n = c->n;
49374a4d8c2SCharles.Forsyth 	int depth = c->v->registers / 4;
49474a4d8c2SCharles.Forsyth 
49574a4d8c2SCharles.Forsyth 	KPRINT("sa = %.8lux\n", c->scriptpa);
49674a4d8c2SCharles.Forsyth 	for (i = 0; i < depth; i++) {
49774a4d8c2SCharles.Forsyth 		int j;
49874a4d8c2SCharles.Forsyth 		for (j = 0; j < 4; j++) {
49974a4d8c2SCharles.Forsyth 			int k = j * depth + i;
50074a4d8c2SCharles.Forsyth 			uchar *p;
50174a4d8c2SCharles.Forsyth 
50274a4d8c2SCharles.Forsyth 			/* display little-endian to make 32-bit values readable */
50374a4d8c2SCharles.Forsyth 			p = (uchar*)n+k*4;
50474a4d8c2SCharles.Forsyth 			if (intr)
50574a4d8c2SCharles.Forsyth 				IPRINT(" %.2x%.2x%.2x%.2x %.2x %.2x", p[3], p[2], p[1], p[0], k * 4, (k * 4) + 0x80);
50674a4d8c2SCharles.Forsyth 			else
50774a4d8c2SCharles.Forsyth 				KPRINT(" %.2x%.2x%.2x%.2x %.2x %.2x", p[3], p[2], p[1], p[0], k * 4, (k * 4) + 0x80);
50874a4d8c2SCharles.Forsyth 			USED(p);
50974a4d8c2SCharles.Forsyth 		}
51074a4d8c2SCharles.Forsyth 		if (intr)
51174a4d8c2SCharles.Forsyth 			IPRINT("\n");
51274a4d8c2SCharles.Forsyth 		else
51374a4d8c2SCharles.Forsyth 			KPRINT("\n");
51474a4d8c2SCharles.Forsyth 	}
51574a4d8c2SCharles.Forsyth }
51674a4d8c2SCharles.Forsyth 
51774a4d8c2SCharles.Forsyth static int
chooserate(Controller * c,int tpf,int * scfp,int * xferpp)51874a4d8c2SCharles.Forsyth chooserate(Controller *c, int tpf, int *scfp, int *xferpp)
51974a4d8c2SCharles.Forsyth {
52074a4d8c2SCharles.Forsyth 	/* find lowest entry >= tpf */
52174a4d8c2SCharles.Forsyth 	int besttpf = 1000;
52274a4d8c2SCharles.Forsyth 	int bestscfi = 0;
52374a4d8c2SCharles.Forsyth 	int bestxferp = 0;
52474a4d8c2SCharles.Forsyth 	int scf, xferp;
52574a4d8c2SCharles.Forsyth 	int maxscf;
52674a4d8c2SCharles.Forsyth 
52774a4d8c2SCharles.Forsyth 	if (c->v->feature & Ultra2)
52874a4d8c2SCharles.Forsyth 		maxscf = NULTRA2SCF;
52974a4d8c2SCharles.Forsyth 	else if (c->v->feature & Ultra)
53074a4d8c2SCharles.Forsyth 		maxscf = NULTRASCF;
53174a4d8c2SCharles.Forsyth 	else
53274a4d8c2SCharles.Forsyth 		maxscf = NSCF;
53374a4d8c2SCharles.Forsyth 
53474a4d8c2SCharles.Forsyth 	/*
53574a4d8c2SCharles.Forsyth 	 * search large clock factors first since this should
53674a4d8c2SCharles.Forsyth 	 * result in more reliable transfers
53774a4d8c2SCharles.Forsyth 	 */
53874a4d8c2SCharles.Forsyth 	for (scf = maxscf; scf >= 1; scf--) {
53974a4d8c2SCharles.Forsyth 		for (xferp = 0; xferp < 8; xferp++) {
54074a4d8c2SCharles.Forsyth 			unsigned char v = c->synctab[scf - 1][xferp];
54174a4d8c2SCharles.Forsyth 			if (v == 0)
54274a4d8c2SCharles.Forsyth 				continue;
54374a4d8c2SCharles.Forsyth 			if (v >= tpf && v < besttpf) {
54474a4d8c2SCharles.Forsyth 				besttpf = v;
54574a4d8c2SCharles.Forsyth 				bestscfi = scf;
54674a4d8c2SCharles.Forsyth 				bestxferp = xferp;
54774a4d8c2SCharles.Forsyth 			}
54874a4d8c2SCharles.Forsyth 		}
54974a4d8c2SCharles.Forsyth 	}
55074a4d8c2SCharles.Forsyth 	if (besttpf == 1000)
55174a4d8c2SCharles.Forsyth 		return 0;
55274a4d8c2SCharles.Forsyth 	if (scfp)
55374a4d8c2SCharles.Forsyth 		*scfp = bestscfi;
55474a4d8c2SCharles.Forsyth 	if (xferpp)
55574a4d8c2SCharles.Forsyth 		*xferpp = bestxferp;
55674a4d8c2SCharles.Forsyth 	return besttpf;
55774a4d8c2SCharles.Forsyth }
55874a4d8c2SCharles.Forsyth 
55974a4d8c2SCharles.Forsyth static void
synctabinit(Controller * c)56074a4d8c2SCharles.Forsyth synctabinit(Controller *c)
56174a4d8c2SCharles.Forsyth {
56274a4d8c2SCharles.Forsyth 	int scf;
56374a4d8c2SCharles.Forsyth 	unsigned long scsilimit;
56474a4d8c2SCharles.Forsyth 	int xferp;
56574a4d8c2SCharles.Forsyth 	unsigned long cr, sr;
56674a4d8c2SCharles.Forsyth 	int tpf;
56774a4d8c2SCharles.Forsyth 	int fast;
56874a4d8c2SCharles.Forsyth 	int maxscf;
56974a4d8c2SCharles.Forsyth 
57074a4d8c2SCharles.Forsyth 	if (c->v->feature & Ultra2)
57174a4d8c2SCharles.Forsyth 		maxscf = NULTRA2SCF;
57274a4d8c2SCharles.Forsyth 	else if (c->v->feature & Ultra)
57374a4d8c2SCharles.Forsyth 		maxscf = NULTRASCF;
57474a4d8c2SCharles.Forsyth 	else
57574a4d8c2SCharles.Forsyth 		maxscf = NSCF;
57674a4d8c2SCharles.Forsyth 
57774a4d8c2SCharles.Forsyth 	/*
57874a4d8c2SCharles.Forsyth 	 * for chips with no clock doubler, but Ultra capable (e.g. 860, or interestingly the
57974a4d8c2SCharles.Forsyth 	 * first spin of the 875), assume 80MHz
58074a4d8c2SCharles.Forsyth 	 * otherwise use the internal (33 Mhz) or external (40MHz) default
58174a4d8c2SCharles.Forsyth 	 */
58274a4d8c2SCharles.Forsyth 
58374a4d8c2SCharles.Forsyth 	if ((c->v->feature & Ultra) != 0 && (c->v->feature & (ClockDouble | ClockQuad)) == 0)
58474a4d8c2SCharles.Forsyth 		c->sclk = ULTRA_NOCLOCKDOUBLE_SCLK;
58574a4d8c2SCharles.Forsyth 	else
58674a4d8c2SCharles.Forsyth 		c->sclk = SCLK;
58774a4d8c2SCharles.Forsyth 
58874a4d8c2SCharles.Forsyth 	/*
58974a4d8c2SCharles.Forsyth 	 * otherwise, if the chip is Ultra capable, but has a slow(ish) clock,
59074a4d8c2SCharles.Forsyth 	 * invoke the doubler
59174a4d8c2SCharles.Forsyth 	 */
59274a4d8c2SCharles.Forsyth 
59374a4d8c2SCharles.Forsyth 	if (SCLK <= 40000000) {
59474a4d8c2SCharles.Forsyth 		if (c->v->feature & ClockDouble) {
59574a4d8c2SCharles.Forsyth 			c->sclk *= 2;
59674a4d8c2SCharles.Forsyth 			c->clockmult = 1;
59774a4d8c2SCharles.Forsyth 		}
59874a4d8c2SCharles.Forsyth 		else if (c->v->feature & ClockQuad) {
59974a4d8c2SCharles.Forsyth 			c->sclk *= 4;
60074a4d8c2SCharles.Forsyth 			c->clockmult = 1;
60174a4d8c2SCharles.Forsyth 		}
60274a4d8c2SCharles.Forsyth 		else
60374a4d8c2SCharles.Forsyth 			c->clockmult = 0;
60474a4d8c2SCharles.Forsyth 	}
60574a4d8c2SCharles.Forsyth 	else
60674a4d8c2SCharles.Forsyth 		c->clockmult = 0;
60774a4d8c2SCharles.Forsyth 
60874a4d8c2SCharles.Forsyth 	/* derive CCF from sclk */
60974a4d8c2SCharles.Forsyth 	/* woebetide anyone with SCLK < 16.7 or > 80MHz */
61074a4d8c2SCharles.Forsyth 	if (c->sclk <= 25 * MEGA)
61174a4d8c2SCharles.Forsyth 		c->ccf = 1;
61274a4d8c2SCharles.Forsyth 	else if (c->sclk <= 3750000)
61374a4d8c2SCharles.Forsyth 		c->ccf = 2;
61474a4d8c2SCharles.Forsyth 	else if (c->sclk <= 50 * MEGA)
61574a4d8c2SCharles.Forsyth 		c->ccf = 3;
61674a4d8c2SCharles.Forsyth 	else if (c->sclk <= 75 * MEGA)
61774a4d8c2SCharles.Forsyth 		c->ccf = 4;
61874a4d8c2SCharles.Forsyth 	else if ((c->v->feature & ClockDouble) && c->sclk <= 80 * MEGA)
61974a4d8c2SCharles.Forsyth 		c->ccf = 5;
62074a4d8c2SCharles.Forsyth 	else if ((c->v->feature & ClockQuad) && c->sclk <= 120 * MEGA)
62174a4d8c2SCharles.Forsyth 		c->ccf = 6;
62274a4d8c2SCharles.Forsyth 	else if ((c->v->feature & ClockQuad) && c->sclk <= 160 * MEGA)
62374a4d8c2SCharles.Forsyth 		c->ccf = 7;
62474a4d8c2SCharles.Forsyth 
62574a4d8c2SCharles.Forsyth 	for (scf = 1; scf < maxscf; scf++) {
62674a4d8c2SCharles.Forsyth 		/* check for legal core rate */
62774a4d8c2SCharles.Forsyth 		/* round up so we run slower for safety */
62874a4d8c2SCharles.Forsyth 	   	cr = (c->sclk * 2 + cf2[scf] - 1) / cf2[scf];
62974a4d8c2SCharles.Forsyth 		if (cr <= MAXSYNCCORERATE) {
63074a4d8c2SCharles.Forsyth 			scsilimit = MAXSYNCSCSIRATE;
63174a4d8c2SCharles.Forsyth 			fast = 0;
63274a4d8c2SCharles.Forsyth 		}
63374a4d8c2SCharles.Forsyth 		else if (cr <= MAXFASTSYNCCORERATE) {
63474a4d8c2SCharles.Forsyth 			scsilimit = MAXFASTSYNCSCSIRATE;
63574a4d8c2SCharles.Forsyth 			fast = 1;
63674a4d8c2SCharles.Forsyth 		}
63774a4d8c2SCharles.Forsyth 		else if ((c->v->feature & Ultra) && cr <= MAXULTRASYNCCORERATE) {
63874a4d8c2SCharles.Forsyth 			scsilimit = MAXULTRASYNCSCSIRATE;
63974a4d8c2SCharles.Forsyth 			fast = 2;
64074a4d8c2SCharles.Forsyth 		}
64174a4d8c2SCharles.Forsyth 		else if ((c->v->feature & Ultra2) && cr <= MAXULTRA2SYNCCORERATE) {
64274a4d8c2SCharles.Forsyth 			scsilimit = MAXULTRA2SYNCSCSIRATE;
64374a4d8c2SCharles.Forsyth 			fast = 3;
64474a4d8c2SCharles.Forsyth 		}
64574a4d8c2SCharles.Forsyth 		else
64674a4d8c2SCharles.Forsyth 			continue;
64774a4d8c2SCharles.Forsyth 		for (xferp = 11; xferp >= 4; xferp--) {
64874a4d8c2SCharles.Forsyth 			int ok;
64974a4d8c2SCharles.Forsyth 			int tp;
65074a4d8c2SCharles.Forsyth 			/* calculate scsi rate - round up again */
65174a4d8c2SCharles.Forsyth 			/* start from sclk for accuracy */
65274a4d8c2SCharles.Forsyth 			int totaldivide = xferp * cf2[scf];
65374a4d8c2SCharles.Forsyth 			sr = (c->sclk * 2 + totaldivide - 1) / totaldivide;
65474a4d8c2SCharles.Forsyth 			if (sr > scsilimit)
65574a4d8c2SCharles.Forsyth 				break;
65674a4d8c2SCharles.Forsyth 			/*
65774a4d8c2SCharles.Forsyth 			 * now work out transfer period
65874a4d8c2SCharles.Forsyth 			 * round down now so that period is pessimistic
65974a4d8c2SCharles.Forsyth 			 */
66074a4d8c2SCharles.Forsyth 			tp = (MEGA * 1000) / sr;
66174a4d8c2SCharles.Forsyth 			/*
66274a4d8c2SCharles.Forsyth 			 * bounds check it
66374a4d8c2SCharles.Forsyth 			 */
66474a4d8c2SCharles.Forsyth 			if (tp < 25 || tp > 255 * 4)
66574a4d8c2SCharles.Forsyth 				continue;
66674a4d8c2SCharles.Forsyth 			/*
66774a4d8c2SCharles.Forsyth 			 * spot stupid special case for Ultra or Ultra2
66874a4d8c2SCharles.Forsyth 			 * while working out factor
66974a4d8c2SCharles.Forsyth 			 */
67074a4d8c2SCharles.Forsyth 			if (tp == 25)
67174a4d8c2SCharles.Forsyth 				tpf = 10;
67274a4d8c2SCharles.Forsyth 			else if (tp == 50)
67374a4d8c2SCharles.Forsyth 				tpf = 12;
67474a4d8c2SCharles.Forsyth 			else if (tp < 52)
67574a4d8c2SCharles.Forsyth 				continue;
67674a4d8c2SCharles.Forsyth 			else
67774a4d8c2SCharles.Forsyth 				tpf = tp / 4;
67874a4d8c2SCharles.Forsyth 			/*
67974a4d8c2SCharles.Forsyth 			 * now check tpf looks sensible
68074a4d8c2SCharles.Forsyth 			 * given core rate
68174a4d8c2SCharles.Forsyth 			 */
68274a4d8c2SCharles.Forsyth 			switch (fast) {
68374a4d8c2SCharles.Forsyth 			case 0:
68474a4d8c2SCharles.Forsyth 				/* scf must be ccf for SCSI 1 */
68574a4d8c2SCharles.Forsyth 				ok = tpf >= 50 && scf == c->ccf;
68674a4d8c2SCharles.Forsyth 				break;
68774a4d8c2SCharles.Forsyth 			case 1:
68874a4d8c2SCharles.Forsyth 				ok = tpf >= 25 && tpf < 50;
68974a4d8c2SCharles.Forsyth 				break;
69074a4d8c2SCharles.Forsyth 			case 2:
69174a4d8c2SCharles.Forsyth 				/*
69274a4d8c2SCharles.Forsyth 				 * must use xferp of 4, or 5 at a pinch
69374a4d8c2SCharles.Forsyth 				 * for an Ultra transfer
69474a4d8c2SCharles.Forsyth 				 */
69574a4d8c2SCharles.Forsyth 				ok = xferp <= 5 && tpf >= 12 && tpf < 25;
69674a4d8c2SCharles.Forsyth 				break;
69774a4d8c2SCharles.Forsyth 			case 3:
69874a4d8c2SCharles.Forsyth 				ok = xferp == 4 && (tpf == 10 || tpf == 11);
69974a4d8c2SCharles.Forsyth 				break;
70074a4d8c2SCharles.Forsyth 			default:
70174a4d8c2SCharles.Forsyth 				ok = 0;
70274a4d8c2SCharles.Forsyth 			}
70374a4d8c2SCharles.Forsyth 			if (!ok)
70474a4d8c2SCharles.Forsyth 				continue;
70574a4d8c2SCharles.Forsyth 			c->synctab[scf - 1][xferp - 4] = tpf;
70674a4d8c2SCharles.Forsyth 		}
70774a4d8c2SCharles.Forsyth 	}
70874a4d8c2SCharles.Forsyth 
70974a4d8c2SCharles.Forsyth #ifndef NO_ULTRA2
71074a4d8c2SCharles.Forsyth 	if (c->v->feature & Ultra2)
71174a4d8c2SCharles.Forsyth 		tpf = 10;
71274a4d8c2SCharles.Forsyth 	else
71374a4d8c2SCharles.Forsyth #endif
71474a4d8c2SCharles.Forsyth 	if (c->v->feature & Ultra)
71574a4d8c2SCharles.Forsyth 		tpf = 12;
71674a4d8c2SCharles.Forsyth 	else
71774a4d8c2SCharles.Forsyth 		tpf = 25;
71874a4d8c2SCharles.Forsyth 	for (; tpf < 256; tpf++) {
71974a4d8c2SCharles.Forsyth 		if (chooserate(c, tpf, &scf, &xferp) == tpf) {
72074a4d8c2SCharles.Forsyth 			unsigned tp = tpf == 10 ? 25 : (tpf == 12 ? 50 : tpf * 4);
72174a4d8c2SCharles.Forsyth 			unsigned long khz = (MEGA + tp - 1) / (tp);
72274a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: tpf=%d scf=%d.%.1d xferp=%d mhz=%ld.%.3ld\n",
72374a4d8c2SCharles.Forsyth 			    tpf, cf2[scf] / 2, (cf2[scf] & 1) ? 5 : 0,
72474a4d8c2SCharles.Forsyth 			    xferp + 4, khz / 1000, khz % 1000);
72574a4d8c2SCharles.Forsyth 			USED(khz);
72674a4d8c2SCharles.Forsyth 			if (c->tpf == 0)
72774a4d8c2SCharles.Forsyth 				c->tpf = tpf;	/* note lowest value for controller */
72874a4d8c2SCharles.Forsyth 		}
72974a4d8c2SCharles.Forsyth 	}
73074a4d8c2SCharles.Forsyth }
73174a4d8c2SCharles.Forsyth 
73274a4d8c2SCharles.Forsyth static void
synctodsa(Dsa * dsa,Controller * c)73374a4d8c2SCharles.Forsyth synctodsa(Dsa *dsa, Controller *c)
73474a4d8c2SCharles.Forsyth {
73574a4d8c2SCharles.Forsyth /*
73674a4d8c2SCharles.Forsyth 	KPRINT("synctodsa(dsa=%lux, target=%d, scntl3=%.2lx sxfer=%.2x)\n",
73774a4d8c2SCharles.Forsyth 	    dsa, dsa->target, c->scntl3[dsa->target], c->sxfer[dsa->target]);
73874a4d8c2SCharles.Forsyth */
73974a4d8c2SCharles.Forsyth 	dsa->scntl3 = c->scntl3[dsa->target];
74074a4d8c2SCharles.Forsyth 	dsa->sxfer = c->sxfer[dsa->target];
74174a4d8c2SCharles.Forsyth }
74274a4d8c2SCharles.Forsyth 
74374a4d8c2SCharles.Forsyth static void
setsync(Dsa * dsa,Controller * c,int target,uchar ultra,uchar scf,uchar xferp,uchar reqack)74474a4d8c2SCharles.Forsyth setsync(Dsa *dsa, Controller *c, int target, uchar ultra, uchar scf, uchar xferp, uchar reqack)
74574a4d8c2SCharles.Forsyth {
74674a4d8c2SCharles.Forsyth 	c->scntl3[target] =
74774a4d8c2SCharles.Forsyth 	    (c->scntl3[target] & 0x08) | (((scf << 4) | c->ccf | (ultra << 7)) & ~0x08);
74874a4d8c2SCharles.Forsyth 	c->sxfer[target] = (xferp << 5) | reqack;
74974a4d8c2SCharles.Forsyth 	c->s[target] = BothDone;
75074a4d8c2SCharles.Forsyth 	if (dsa) {
75174a4d8c2SCharles.Forsyth 		synctodsa(dsa, c);
75274a4d8c2SCharles.Forsyth 		c->n->scntl3 = c->scntl3[target];
75374a4d8c2SCharles.Forsyth 		c->n->sxfer = c->sxfer[target];
75474a4d8c2SCharles.Forsyth 	}
75574a4d8c2SCharles.Forsyth }
75674a4d8c2SCharles.Forsyth 
75774a4d8c2SCharles.Forsyth static void
setasync(Dsa * dsa,Controller * c,int target)75874a4d8c2SCharles.Forsyth setasync(Dsa *dsa, Controller *c, int target)
75974a4d8c2SCharles.Forsyth {
76074a4d8c2SCharles.Forsyth 	setsync(dsa, c, target, 0, c->ccf, 0, 0);
76174a4d8c2SCharles.Forsyth }
76274a4d8c2SCharles.Forsyth 
76374a4d8c2SCharles.Forsyth static void
setwide(Dsa * dsa,Controller * c,int target,uchar wide)76474a4d8c2SCharles.Forsyth setwide(Dsa *dsa, Controller *c, int target, uchar wide)
76574a4d8c2SCharles.Forsyth {
76674a4d8c2SCharles.Forsyth 	c->scntl3[target] = wide ? (1 << 3) : 0;
76774a4d8c2SCharles.Forsyth 	setasync(dsa, c, target);
76874a4d8c2SCharles.Forsyth 	c->s[target] = WideDone;
76974a4d8c2SCharles.Forsyth }
77074a4d8c2SCharles.Forsyth 
77174a4d8c2SCharles.Forsyth static int
buildsdtrmsg(uchar * buf,uchar tpf,uchar offset)77274a4d8c2SCharles.Forsyth buildsdtrmsg(uchar *buf, uchar tpf, uchar offset)
77374a4d8c2SCharles.Forsyth {
77474a4d8c2SCharles.Forsyth 	*buf++ = X_MSG;
77574a4d8c2SCharles.Forsyth 	*buf++ = 3;
77674a4d8c2SCharles.Forsyth 	*buf++ = X_MSG_SDTR;
77774a4d8c2SCharles.Forsyth 	*buf++ = tpf;
77874a4d8c2SCharles.Forsyth 	*buf = offset;
77974a4d8c2SCharles.Forsyth 	return 5;
78074a4d8c2SCharles.Forsyth }
78174a4d8c2SCharles.Forsyth 
78274a4d8c2SCharles.Forsyth static int
buildwdtrmsg(uchar * buf,uchar expo)78374a4d8c2SCharles.Forsyth buildwdtrmsg(uchar *buf, uchar expo)
78474a4d8c2SCharles.Forsyth {
78574a4d8c2SCharles.Forsyth 	*buf++ = X_MSG;
78674a4d8c2SCharles.Forsyth 	*buf++ = 2;
78774a4d8c2SCharles.Forsyth 	*buf++ = X_MSG_WDTR;
78874a4d8c2SCharles.Forsyth 	*buf = expo;
78974a4d8c2SCharles.Forsyth 	return 4;
79074a4d8c2SCharles.Forsyth }
79174a4d8c2SCharles.Forsyth 
79274a4d8c2SCharles.Forsyth static void
start(Controller * c,long entry)79374a4d8c2SCharles.Forsyth start(Controller *c, long entry)
79474a4d8c2SCharles.Forsyth {
79574a4d8c2SCharles.Forsyth 	ulong p;
79674a4d8c2SCharles.Forsyth 
79774a4d8c2SCharles.Forsyth 	if (c->running)
79874a4d8c2SCharles.Forsyth 		panic("sd53c8xx: start called while running");
79974a4d8c2SCharles.Forsyth 	c->running = 1;
80074a4d8c2SCharles.Forsyth 	p = c->scriptpa + entry;
80174a4d8c2SCharles.Forsyth 	lesetl(c->n->dsp, p);
80274a4d8c2SCharles.Forsyth 	if (c->ssm)
80374a4d8c2SCharles.Forsyth 		c->n->dcntl |= 0x4;		/* start DMA in SSI mode */
80474a4d8c2SCharles.Forsyth }
80574a4d8c2SCharles.Forsyth 
80674a4d8c2SCharles.Forsyth static void
ncrcontinue(Controller * c)80774a4d8c2SCharles.Forsyth ncrcontinue(Controller *c)
80874a4d8c2SCharles.Forsyth {
80974a4d8c2SCharles.Forsyth 	if (c->running)
81074a4d8c2SCharles.Forsyth 		panic("sd53c8xx: ncrcontinue called while running");
81174a4d8c2SCharles.Forsyth 	/* set the start DMA bit to continue execution */
81274a4d8c2SCharles.Forsyth 	c->running = 1;
81374a4d8c2SCharles.Forsyth 	c->n->dcntl |= 0x4;
81474a4d8c2SCharles.Forsyth }
81574a4d8c2SCharles.Forsyth 
81674a4d8c2SCharles.Forsyth static void
softreset(Controller * c)81774a4d8c2SCharles.Forsyth softreset(Controller *c)
81874a4d8c2SCharles.Forsyth {
81974a4d8c2SCharles.Forsyth 	Ncr *n = c->n;
82074a4d8c2SCharles.Forsyth 
82174a4d8c2SCharles.Forsyth 	n->istat = Srst;		/* software reset */
82274a4d8c2SCharles.Forsyth 	n->istat = 0;
82374a4d8c2SCharles.Forsyth 	/* general initialisation */
82474a4d8c2SCharles.Forsyth 	n->scid = (1 << 6) | 7;		/* respond to reselect, ID 7 */
82574a4d8c2SCharles.Forsyth 	n->respid = 1 << 7;		/* response ID = 7 */
82674a4d8c2SCharles.Forsyth 
82774a4d8c2SCharles.Forsyth #ifdef INTERNAL_SCLK
82874a4d8c2SCharles.Forsyth 	n->stest1 = 0x80;		/* disable external scsi clock */
82974a4d8c2SCharles.Forsyth #else
83074a4d8c2SCharles.Forsyth 	n->stest1 = 0x00;
83174a4d8c2SCharles.Forsyth #endif
83274a4d8c2SCharles.Forsyth 
83374a4d8c2SCharles.Forsyth 	n->stime0 = 0xdd;		/* about 0.5 second timeout on each device */
83474a4d8c2SCharles.Forsyth 	n->scntl0 |= 0x8;		/* Enable parity checking */
83574a4d8c2SCharles.Forsyth 
83674a4d8c2SCharles.Forsyth 	/* continued setup */
83774a4d8c2SCharles.Forsyth 	n->sien0 = 0x8f;
83874a4d8c2SCharles.Forsyth 	n->sien1 = 0x04;
83974a4d8c2SCharles.Forsyth 	n->dien = 0x7d;
84074a4d8c2SCharles.Forsyth 	n->stest3 = 0x80;		/* TolerANT enable */
84174a4d8c2SCharles.Forsyth 	c->running = 0;
84274a4d8c2SCharles.Forsyth 
84374a4d8c2SCharles.Forsyth 	if (c->v->feature & BigFifo)
84474a4d8c2SCharles.Forsyth 		n->ctest5 = (1 << 5);
84574a4d8c2SCharles.Forsyth 	n->dmode = c->v->burst << 6;	/* set burst length bits */
84674a4d8c2SCharles.Forsyth 	if (c->v->burst & 4)
84774a4d8c2SCharles.Forsyth 		n->ctest5 |= (1 << 2);	/* including overflow into ctest5 bit 2 */
84874a4d8c2SCharles.Forsyth 	if (c->v->feature & Prefetch)
84974a4d8c2SCharles.Forsyth 		n->dcntl |= (1 << 5);	/* prefetch enable */
85074a4d8c2SCharles.Forsyth 	else if (c->v->feature & BurstOpCodeFetch)
85174a4d8c2SCharles.Forsyth 		n->dmode |= (1 << 1);	/* burst opcode fetch */
85274a4d8c2SCharles.Forsyth 	if (c->v->feature & Differential) {
85374a4d8c2SCharles.Forsyth 		/* chip capable */
85474a4d8c2SCharles.Forsyth 		if ((c->feature & Differential) || bios_set_differential(c)) {
85574a4d8c2SCharles.Forsyth 			/* user enabled, or some evidence bios set differential */
85674a4d8c2SCharles.Forsyth 			if (n->sstat2 & (1 << 2))
85774a4d8c2SCharles.Forsyth 				print("sd53c8xx: can't go differential; wrong cable\n");
85874a4d8c2SCharles.Forsyth 			else {
85974a4d8c2SCharles.Forsyth 				n->stest2 = (1 << 5);
86074a4d8c2SCharles.Forsyth 				print("sd53c8xx: differential mode set\n");
86174a4d8c2SCharles.Forsyth 			}
86274a4d8c2SCharles.Forsyth 		}
86374a4d8c2SCharles.Forsyth 	}
86474a4d8c2SCharles.Forsyth 	if (c->clockmult) {
86574a4d8c2SCharles.Forsyth 		n->stest1 |= (1 << 3);	/* power up doubler */
86674a4d8c2SCharles.Forsyth 		delay(2);
86774a4d8c2SCharles.Forsyth 		n->stest3 |= (1 << 5);	/* stop clock */
86874a4d8c2SCharles.Forsyth 		n->stest1 |= (1 << 2);	/* enable doubler */
86974a4d8c2SCharles.Forsyth 		n->stest3 &= ~(1 << 5);	/* start clock */
87074a4d8c2SCharles.Forsyth 		/* pray */
87174a4d8c2SCharles.Forsyth 	}
87274a4d8c2SCharles.Forsyth }
87374a4d8c2SCharles.Forsyth 
87474a4d8c2SCharles.Forsyth static void
msgsm(Dsa * dsa,Controller * c,int msg,int * cont,int * wakeme)87574a4d8c2SCharles.Forsyth msgsm(Dsa *dsa, Controller *c, int msg, int *cont, int *wakeme)
87674a4d8c2SCharles.Forsyth {
87774a4d8c2SCharles.Forsyth 	uchar histpf, hisreqack;
87874a4d8c2SCharles.Forsyth 	int tpf;
87974a4d8c2SCharles.Forsyth 	int scf, xferp;
88074a4d8c2SCharles.Forsyth 	int len;
88174a4d8c2SCharles.Forsyth 
88274a4d8c2SCharles.Forsyth 	Ncr *n = c->n;
88374a4d8c2SCharles.Forsyth 
88474a4d8c2SCharles.Forsyth 	switch (c->s[dsa->target]) {
88574a4d8c2SCharles.Forsyth 	case SyncInit:
88674a4d8c2SCharles.Forsyth 		switch (msg) {
88774a4d8c2SCharles.Forsyth 		case A_SIR_MSG_SDTR:
88874a4d8c2SCharles.Forsyth 			/* reply to my SDTR */
88974a4d8c2SCharles.Forsyth 			histpf = n->scratcha[2];
89074a4d8c2SCharles.Forsyth 			hisreqack = n->scratcha[3];
89174a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: SDTN response %d %d\n",
89274a4d8c2SCharles.Forsyth 			    dsa->target, histpf, hisreqack);
89374a4d8c2SCharles.Forsyth 
89474a4d8c2SCharles.Forsyth 			if (hisreqack == 0)
89574a4d8c2SCharles.Forsyth 				setasync(dsa, c, dsa->target);
89674a4d8c2SCharles.Forsyth 			else {
89774a4d8c2SCharles.Forsyth 				/* hisreqack should be <= c->v->maxsyncoff */
89874a4d8c2SCharles.Forsyth 				tpf = chooserate(c, histpf, &scf, &xferp);
89974a4d8c2SCharles.Forsyth 				KPRINT("sd53c8xx: %d: SDTN: using %d %d\n",
90074a4d8c2SCharles.Forsyth 				    dsa->target, tpf, hisreqack);
90174a4d8c2SCharles.Forsyth 				setsync(dsa, c, dsa->target, tpf < 25, scf, xferp, hisreqack);
90274a4d8c2SCharles.Forsyth 			}
90374a4d8c2SCharles.Forsyth 			*cont = -2;
90474a4d8c2SCharles.Forsyth 			return;
90574a4d8c2SCharles.Forsyth 		case A_SIR_EV_PHASE_SWITCH_AFTER_ID:
90674a4d8c2SCharles.Forsyth 			/* target ignored ATN for message after IDENTIFY - not SCSI-II */
90774a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: illegal phase switch after ID message - SCSI-1 device?\n", dsa->target);
90874a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: SDTN: async\n", dsa->target);
90974a4d8c2SCharles.Forsyth 			setasync(dsa, c, dsa->target);
91074a4d8c2SCharles.Forsyth 			*cont = E_to_decisions;
91174a4d8c2SCharles.Forsyth 			return;
91274a4d8c2SCharles.Forsyth 		case A_SIR_MSG_REJECT:
91374a4d8c2SCharles.Forsyth 			/* rejection of my SDTR */
91474a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: SDTN: rejected SDTR\n", dsa->target);
91574a4d8c2SCharles.Forsyth 		//async:
91674a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: SDTN: async\n", dsa->target);
91774a4d8c2SCharles.Forsyth 			setasync(dsa, c, dsa->target);
91874a4d8c2SCharles.Forsyth 			*cont = -2;
91974a4d8c2SCharles.Forsyth 			return;
92074a4d8c2SCharles.Forsyth 		}
92174a4d8c2SCharles.Forsyth 		break;
92274a4d8c2SCharles.Forsyth 	case WideInit:
92374a4d8c2SCharles.Forsyth 		switch (msg) {
92474a4d8c2SCharles.Forsyth 		case A_SIR_MSG_WDTR:
92574a4d8c2SCharles.Forsyth 			/* reply to my WDTR */
92674a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: WDTN: response %d\n",
92774a4d8c2SCharles.Forsyth 			    dsa->target, n->scratcha[2]);
92874a4d8c2SCharles.Forsyth 			setwide(dsa, c, dsa->target, n->scratcha[2]);
92974a4d8c2SCharles.Forsyth 			*cont = -2;
93074a4d8c2SCharles.Forsyth 			return;
93174a4d8c2SCharles.Forsyth 		case A_SIR_EV_PHASE_SWITCH_AFTER_ID:
93274a4d8c2SCharles.Forsyth 			/* target ignored ATN for message after IDENTIFY - not SCSI-II */
93374a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: illegal phase switch after ID message - SCSI-1 device?\n", dsa->target);
93474a4d8c2SCharles.Forsyth 			setwide(dsa, c, dsa->target, 0);
93574a4d8c2SCharles.Forsyth 			*cont = E_to_decisions;
93674a4d8c2SCharles.Forsyth 			return;
93774a4d8c2SCharles.Forsyth 		case A_SIR_MSG_REJECT:
93874a4d8c2SCharles.Forsyth 			/* rejection of my SDTR */
93974a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: WDTN: rejected WDTR\n", dsa->target);
94074a4d8c2SCharles.Forsyth 			setwide(dsa, c, dsa->target, 0);
94174a4d8c2SCharles.Forsyth 			*cont = -2;
94274a4d8c2SCharles.Forsyth 			return;
94374a4d8c2SCharles.Forsyth 		}
94474a4d8c2SCharles.Forsyth 		break;
94574a4d8c2SCharles.Forsyth 
94674a4d8c2SCharles.Forsyth 	case NeitherDone:
94774a4d8c2SCharles.Forsyth 	case WideDone:
94874a4d8c2SCharles.Forsyth 	case BothDone:
94974a4d8c2SCharles.Forsyth 		switch (msg) {
95074a4d8c2SCharles.Forsyth 		case A_SIR_MSG_WDTR: {
95174a4d8c2SCharles.Forsyth 			uchar hiswide, mywide;
95274a4d8c2SCharles.Forsyth 			hiswide = n->scratcha[2];
95374a4d8c2SCharles.Forsyth 			mywide = (c->v->feature & Wide) != 0;
95474a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: WDTN: target init %d\n",
95574a4d8c2SCharles.Forsyth 			    dsa->target, hiswide);
95674a4d8c2SCharles.Forsyth 			if (hiswide < mywide)
95774a4d8c2SCharles.Forsyth 				mywide = hiswide;
95874a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: WDTN: responding %d\n",
95974a4d8c2SCharles.Forsyth 			    dsa->target, mywide);
96074a4d8c2SCharles.Forsyth 			setwide(dsa, c, dsa->target, mywide);
96174a4d8c2SCharles.Forsyth 			len = buildwdtrmsg(dsa->msg_out, mywide);
96274a4d8c2SCharles.Forsyth 			setmovedata(&dsa->msg_out_buf, DMASEG(dsa->msg_out), len);
96374a4d8c2SCharles.Forsyth 			*cont = E_response;
96474a4d8c2SCharles.Forsyth 			c->s[dsa->target] = WideResponse;
96574a4d8c2SCharles.Forsyth 			return;
96674a4d8c2SCharles.Forsyth 		}
96774a4d8c2SCharles.Forsyth 		case A_SIR_MSG_SDTR:
96874a4d8c2SCharles.Forsyth #ifdef ASYNC_ONLY
96974a4d8c2SCharles.Forsyth 			*cont = E_reject;
97074a4d8c2SCharles.Forsyth 			return;
97174a4d8c2SCharles.Forsyth #else
97274a4d8c2SCharles.Forsyth 			/* target decides to renegotiate */
97374a4d8c2SCharles.Forsyth 			histpf = n->scratcha[2];
97474a4d8c2SCharles.Forsyth 			hisreqack = n->scratcha[3];
97574a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: SDTN: target init %d %d\n",
97674a4d8c2SCharles.Forsyth 			    dsa->target, histpf, hisreqack);
97774a4d8c2SCharles.Forsyth 			if (hisreqack == 0) {
97874a4d8c2SCharles.Forsyth 				/* he wants asynchronous */
97974a4d8c2SCharles.Forsyth 				setasync(dsa, c, dsa->target);
98074a4d8c2SCharles.Forsyth 				tpf = 0;
98174a4d8c2SCharles.Forsyth 			}
98274a4d8c2SCharles.Forsyth 			else {
98374a4d8c2SCharles.Forsyth 				/* he wants synchronous */
98474a4d8c2SCharles.Forsyth 				tpf = chooserate(c, histpf, &scf, &xferp);
98574a4d8c2SCharles.Forsyth 				if (hisreqack > c->v->maxsyncoff)
98674a4d8c2SCharles.Forsyth 					hisreqack = c->v->maxsyncoff;
98774a4d8c2SCharles.Forsyth 				KPRINT("sd53c8xx: %d: using %d %d\n",
98874a4d8c2SCharles.Forsyth 				    dsa->target, tpf, hisreqack);
98974a4d8c2SCharles.Forsyth 				setsync(dsa, c, dsa->target, tpf < 25, scf, xferp, hisreqack);
99074a4d8c2SCharles.Forsyth 			}
99174a4d8c2SCharles.Forsyth 			/* build my SDTR message */
99274a4d8c2SCharles.Forsyth 			len = buildsdtrmsg(dsa->msg_out, tpf, hisreqack);
99374a4d8c2SCharles.Forsyth 			setmovedata(&dsa->msg_out_buf, DMASEG(dsa->msg_out), len);
99474a4d8c2SCharles.Forsyth 			*cont = E_response;
99574a4d8c2SCharles.Forsyth 			c->s[dsa->target] = SyncResponse;
99674a4d8c2SCharles.Forsyth 			return;
99774a4d8c2SCharles.Forsyth #endif
99874a4d8c2SCharles.Forsyth 		}
99974a4d8c2SCharles.Forsyth 		break;
100074a4d8c2SCharles.Forsyth 	case WideResponse:
100174a4d8c2SCharles.Forsyth 		switch (msg) {
100274a4d8c2SCharles.Forsyth 		case A_SIR_EV_RESPONSE_OK:
100374a4d8c2SCharles.Forsyth 			c->s[dsa->target] = WideDone;
100474a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: WDTN: response accepted\n", dsa->target);
100574a4d8c2SCharles.Forsyth 			*cont = -2;
100674a4d8c2SCharles.Forsyth 			return;
100774a4d8c2SCharles.Forsyth 		case A_SIR_MSG_REJECT:
100874a4d8c2SCharles.Forsyth 			setwide(dsa, c, dsa->target, 0);
100974a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: WDTN: response REJECTed\n", dsa->target);
101074a4d8c2SCharles.Forsyth 			*cont = -2;
101174a4d8c2SCharles.Forsyth 			return;
101274a4d8c2SCharles.Forsyth 		}
101374a4d8c2SCharles.Forsyth 		break;
101474a4d8c2SCharles.Forsyth 	case SyncResponse:
101574a4d8c2SCharles.Forsyth 		switch (msg) {
101674a4d8c2SCharles.Forsyth 		case A_SIR_EV_RESPONSE_OK:
101774a4d8c2SCharles.Forsyth 			c->s[dsa->target] = BothDone;
101874a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: SDTN: response accepted (%s)\n",
101974a4d8c2SCharles.Forsyth 			    dsa->target, phase[n->sstat1 & 7]);
102074a4d8c2SCharles.Forsyth 			*cont = -2;
102174a4d8c2SCharles.Forsyth 			return;	/* chf */
102274a4d8c2SCharles.Forsyth 		case A_SIR_MSG_REJECT:
102374a4d8c2SCharles.Forsyth 			setasync(dsa, c, dsa->target);
102474a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: SDTN: response REJECTed\n", dsa->target);
102574a4d8c2SCharles.Forsyth 			*cont = -2;
102674a4d8c2SCharles.Forsyth 			return;
102774a4d8c2SCharles.Forsyth 		}
102874a4d8c2SCharles.Forsyth 		break;
102974a4d8c2SCharles.Forsyth 	}
103074a4d8c2SCharles.Forsyth 	KPRINT("sd53c8xx: %d: msgsm: state %d msg %d\n",
103174a4d8c2SCharles.Forsyth 	    dsa->target, c->s[dsa->target], msg);
103274a4d8c2SCharles.Forsyth 	*wakeme = 1;
103374a4d8c2SCharles.Forsyth 	return;
103474a4d8c2SCharles.Forsyth }
103574a4d8c2SCharles.Forsyth 
103674a4d8c2SCharles.Forsyth static void
calcblockdma(Dsa * d,ulong base,ulong count)103774a4d8c2SCharles.Forsyth calcblockdma(Dsa *d, ulong base, ulong count)
103874a4d8c2SCharles.Forsyth {
103974a4d8c2SCharles.Forsyth 	ulong blocks;
104074a4d8c2SCharles.Forsyth 	if (DEBUG(3))
104174a4d8c2SCharles.Forsyth 		blocks = 0;
104274a4d8c2SCharles.Forsyth 	else {
104374a4d8c2SCharles.Forsyth 		blocks = count / A_BSIZE;
104474a4d8c2SCharles.Forsyth 		if (blocks > 255)
104574a4d8c2SCharles.Forsyth 			blocks = 255;
104674a4d8c2SCharles.Forsyth 	}
104774a4d8c2SCharles.Forsyth 	d->dmablks = blocks;
104874a4d8c2SCharles.Forsyth 	d->dmaaddr[0] = base;
104974a4d8c2SCharles.Forsyth 	d->dmaaddr[1] = base >> 8;
105074a4d8c2SCharles.Forsyth 	d->dmaaddr[2] = base >> 16;
105174a4d8c2SCharles.Forsyth 	d->dmaaddr[3] = base >> 24;
105274a4d8c2SCharles.Forsyth 	setmovedata(&d->data_buf, base + blocks * A_BSIZE, count - blocks * A_BSIZE);
105374a4d8c2SCharles.Forsyth 	if (legetl(d->data_buf.dbc) == 0)
105474a4d8c2SCharles.Forsyth 		d->flag = 1;
105574a4d8c2SCharles.Forsyth }
105674a4d8c2SCharles.Forsyth 
105774a4d8c2SCharles.Forsyth static ulong
read_mismatch_recover(Controller * c,Ncr * n,Dsa * dsa)105874a4d8c2SCharles.Forsyth read_mismatch_recover(Controller *c, Ncr *n, Dsa *dsa)
105974a4d8c2SCharles.Forsyth {
106074a4d8c2SCharles.Forsyth 	ulong dbc;
106174a4d8c2SCharles.Forsyth 	uchar dfifo = n->dfifo;
106274a4d8c2SCharles.Forsyth 	int inchip;
106374a4d8c2SCharles.Forsyth 
106474a4d8c2SCharles.Forsyth 	dbc = (n->dbc[2]<<16)|(n->dbc[1]<<8)|n->dbc[0];
106574a4d8c2SCharles.Forsyth 	if (n->ctest5 & (1 << 5))
106674a4d8c2SCharles.Forsyth 		inchip = ((dfifo | ((n->ctest5 & 3) << 8)) - (dbc & 0x3ff)) & 0x3ff;
106774a4d8c2SCharles.Forsyth 	else
106874a4d8c2SCharles.Forsyth 		inchip = ((dfifo & 0x7f) - (dbc & 0x7f)) & 0x7f;
106974a4d8c2SCharles.Forsyth 	if (inchip) {
107074a4d8c2SCharles.Forsyth 		IPRINT("sd53c8xx: %d/%d: read_mismatch_recover: DMA FIFO = %d\n",
107174a4d8c2SCharles.Forsyth 		    dsa->target, dsa->lun, inchip);
107274a4d8c2SCharles.Forsyth 	}
107374a4d8c2SCharles.Forsyth 	if (n->sxfer & 0xf) {
107474a4d8c2SCharles.Forsyth 		/* SCSI FIFO */
107574a4d8c2SCharles.Forsyth 		uchar fifo = n->sstat1 >> 4;
107674a4d8c2SCharles.Forsyth 		if (c->v->maxsyncoff > 8)
107774a4d8c2SCharles.Forsyth 			fifo |= (n->sstat2 & (1 << 4));
107874a4d8c2SCharles.Forsyth 		if (fifo) {
107974a4d8c2SCharles.Forsyth 			inchip += fifo;
108074a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: %d/%d: read_mismatch_recover: SCSI FIFO = %d\n",
108174a4d8c2SCharles.Forsyth 			    dsa->target, dsa->lun, fifo);
108274a4d8c2SCharles.Forsyth 		}
108374a4d8c2SCharles.Forsyth 	}
108474a4d8c2SCharles.Forsyth 	else {
108574a4d8c2SCharles.Forsyth 		if (n->sstat0 & (1 << 7)) {
108674a4d8c2SCharles.Forsyth 			inchip++;
108774a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: %d/%d: read_mismatch_recover: SIDL full\n",
108874a4d8c2SCharles.Forsyth 			    dsa->target, dsa->lun);
108974a4d8c2SCharles.Forsyth 		}
109074a4d8c2SCharles.Forsyth 		if (n->sstat2 & (1 << 7)) {
109174a4d8c2SCharles.Forsyth 			inchip++;
109274a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: %d/%d: read_mismatch_recover: SIDL msb full\n",
109374a4d8c2SCharles.Forsyth 			    dsa->target, dsa->lun);
109474a4d8c2SCharles.Forsyth 		}
109574a4d8c2SCharles.Forsyth 	}
109674a4d8c2SCharles.Forsyth 	USED(inchip);
109774a4d8c2SCharles.Forsyth 	return dbc;
109874a4d8c2SCharles.Forsyth }
109974a4d8c2SCharles.Forsyth 
110074a4d8c2SCharles.Forsyth static ulong
write_mismatch_recover(Ncr * n,Dsa * dsa)110174a4d8c2SCharles.Forsyth write_mismatch_recover(Ncr *n, Dsa *dsa)
110274a4d8c2SCharles.Forsyth {
110374a4d8c2SCharles.Forsyth 	ulong dbc;
110474a4d8c2SCharles.Forsyth 	uchar dfifo = n->dfifo;
110574a4d8c2SCharles.Forsyth 	int inchip;
110674a4d8c2SCharles.Forsyth 
110774a4d8c2SCharles.Forsyth 	dbc = (n->dbc[2]<<16)|(n->dbc[1]<<8)|n->dbc[0];
110874a4d8c2SCharles.Forsyth 	USED(dsa);
110974a4d8c2SCharles.Forsyth 	if (n->ctest5 & (1 << 5))
111074a4d8c2SCharles.Forsyth 		inchip = ((dfifo | ((n->ctest5 & 3) << 8)) - (dbc & 0x3ff)) & 0x3ff;
111174a4d8c2SCharles.Forsyth 	else
111274a4d8c2SCharles.Forsyth 		inchip = ((dfifo & 0x7f) - (dbc & 0x7f)) & 0x7f;
111374a4d8c2SCharles.Forsyth #ifdef WMR_DEBUG
111474a4d8c2SCharles.Forsyth 	if (inchip) {
111574a4d8c2SCharles.Forsyth 		IPRINT("sd53c8xx: %d/%d: write_mismatch_recover: DMA FIFO = %d\n",
111674a4d8c2SCharles.Forsyth 		    dsa->target, dsa->lun, inchip);
111774a4d8c2SCharles.Forsyth 	}
111874a4d8c2SCharles.Forsyth #endif
111974a4d8c2SCharles.Forsyth 	if (n->sstat0 & (1 << 5)) {
112074a4d8c2SCharles.Forsyth 		inchip++;
112174a4d8c2SCharles.Forsyth #ifdef WMR_DEBUG
112274a4d8c2SCharles.Forsyth 		IPRINT("sd53c8xx: %d/%d: write_mismatch_recover: SODL full\n", dsa->target, dsa->lun);
112374a4d8c2SCharles.Forsyth #endif
112474a4d8c2SCharles.Forsyth 	}
112574a4d8c2SCharles.Forsyth 	if (n->sstat2 & (1 << 5)) {
112674a4d8c2SCharles.Forsyth 		inchip++;
112774a4d8c2SCharles.Forsyth #ifdef WMR_DEBUG
112874a4d8c2SCharles.Forsyth 		IPRINT("sd53c8xx: %d/%d: write_mismatch_recover: SODL msb full\n", dsa->target, dsa->lun);
112974a4d8c2SCharles.Forsyth #endif
113074a4d8c2SCharles.Forsyth 	}
113174a4d8c2SCharles.Forsyth 	if (n->sxfer & 0xf) {
113274a4d8c2SCharles.Forsyth 		/* synchronous SODR */
113374a4d8c2SCharles.Forsyth 		if (n->sstat0 & (1 << 6)) {
113474a4d8c2SCharles.Forsyth 			inchip++;
113574a4d8c2SCharles.Forsyth #ifdef WMR_DEBUG
113674a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: %d/%d: write_mismatch_recover: SODR full\n",
113774a4d8c2SCharles.Forsyth 			    dsa->target, dsa->lun);
113874a4d8c2SCharles.Forsyth #endif
113974a4d8c2SCharles.Forsyth 		}
114074a4d8c2SCharles.Forsyth 		if (n->sstat2 & (1 << 6)) {
114174a4d8c2SCharles.Forsyth 			inchip++;
114274a4d8c2SCharles.Forsyth #ifdef WMR_DEBUG
114374a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: %d/%d: write_mismatch_recover: SODR msb full\n",
114474a4d8c2SCharles.Forsyth 			    dsa->target, dsa->lun);
114574a4d8c2SCharles.Forsyth #endif
114674a4d8c2SCharles.Forsyth 		}
114774a4d8c2SCharles.Forsyth 	}
114874a4d8c2SCharles.Forsyth 	/* clear the dma fifo */
114974a4d8c2SCharles.Forsyth 	n->ctest3 |= (1 << 2);
115074a4d8c2SCharles.Forsyth 	/* wait till done */
115174a4d8c2SCharles.Forsyth 	while ((n->dstat & Dfe) == 0)
115274a4d8c2SCharles.Forsyth 		;
115374a4d8c2SCharles.Forsyth 	return dbc + inchip;
115474a4d8c2SCharles.Forsyth }
115574a4d8c2SCharles.Forsyth 
115674a4d8c2SCharles.Forsyth static void
interrupt(Ureg * ur,void * a)115774a4d8c2SCharles.Forsyth interrupt(Ureg *ur, void *a)
115874a4d8c2SCharles.Forsyth {
115974a4d8c2SCharles.Forsyth 	uchar istat;
116074a4d8c2SCharles.Forsyth 	ushort sist;
116174a4d8c2SCharles.Forsyth 	uchar dstat;
116274a4d8c2SCharles.Forsyth 	int wakeme = 0;
116374a4d8c2SCharles.Forsyth 	int cont = -1;
116474a4d8c2SCharles.Forsyth 	Dsa *dsa;
116574a4d8c2SCharles.Forsyth 	Controller *c = a;
116674a4d8c2SCharles.Forsyth 	Ncr *n = c->n;
116774a4d8c2SCharles.Forsyth 
116874a4d8c2SCharles.Forsyth 	USED(ur);
116974a4d8c2SCharles.Forsyth 	if (DEBUG(1))
117074a4d8c2SCharles.Forsyth 		IPRINT("sd53c8xx: int\n");
117174a4d8c2SCharles.Forsyth 	ilock(c);
117274a4d8c2SCharles.Forsyth 	istat = n->istat;
117374a4d8c2SCharles.Forsyth 	if (istat & Intf) {
117474a4d8c2SCharles.Forsyth 		Dsa *d;
117574a4d8c2SCharles.Forsyth 		int wokesomething = 0;
117674a4d8c2SCharles.Forsyth 		if (DEBUG(1))
117774a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: Intfly\n");
117874a4d8c2SCharles.Forsyth 		n->istat = Intf;
117974a4d8c2SCharles.Forsyth 		/* search for structures in A_STATE_DONE */
118074a4d8c2SCharles.Forsyth 		for (d = KPTR(legetl(c->dsalist.head)); d; d = KPTR(legetl(d->next))) {
118174a4d8c2SCharles.Forsyth 			if (d->stateb == A_STATE_DONE) {
118274a4d8c2SCharles.Forsyth 				d->p9status = d->status;
118374a4d8c2SCharles.Forsyth 				if (DEBUG(1))
118474a4d8c2SCharles.Forsyth 					IPRINT("sd53c8xx: waking up dsa %lux\n", d);
118574a4d8c2SCharles.Forsyth 				wakeup(d);
118674a4d8c2SCharles.Forsyth 				wokesomething = 1;
118774a4d8c2SCharles.Forsyth 			}
118874a4d8c2SCharles.Forsyth 		}
118974a4d8c2SCharles.Forsyth 		if (!wokesomething)
119074a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: nothing to wake up\n");
119174a4d8c2SCharles.Forsyth 	}
119274a4d8c2SCharles.Forsyth 
119374a4d8c2SCharles.Forsyth 	if ((istat & (Sip | Dip)) == 0) {
119474a4d8c2SCharles.Forsyth 		if (DEBUG(1))
119574a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: int end %x\n", istat);
119674a4d8c2SCharles.Forsyth 		iunlock(c);
119774a4d8c2SCharles.Forsyth 		return;
119874a4d8c2SCharles.Forsyth 	}
119974a4d8c2SCharles.Forsyth 
120074a4d8c2SCharles.Forsyth 	sist = (n->sist1<<8)|n->sist0;	/* BUG? can two-byte read be inconsistent? */
120174a4d8c2SCharles.Forsyth 	dstat = n->dstat;
120274a4d8c2SCharles.Forsyth 	dsa = (Dsa *)DMASEG_TO_KADDR(legetl(n->dsa));
120374a4d8c2SCharles.Forsyth 	c->running = 0;
120474a4d8c2SCharles.Forsyth 	if (istat & Sip) {
120574a4d8c2SCharles.Forsyth 		if (DEBUG(1))
120674a4d8c2SCharles.Forsyth 			IPRINT("sist = %.4x\n", sist);
120774a4d8c2SCharles.Forsyth 		if (sist & 0x80) {
120874a4d8c2SCharles.Forsyth 			ulong addr;
120974a4d8c2SCharles.Forsyth 			ulong sa;
121074a4d8c2SCharles.Forsyth 			ulong dbc;
121174a4d8c2SCharles.Forsyth 			ulong tbc;
121274a4d8c2SCharles.Forsyth 			int dmablks;
121374a4d8c2SCharles.Forsyth 			ulong dmaaddr;
121474a4d8c2SCharles.Forsyth 
121574a4d8c2SCharles.Forsyth 			addr = legetl(n->dsp);
121674a4d8c2SCharles.Forsyth 			sa = addr - c->scriptpa;
121774a4d8c2SCharles.Forsyth 			if (DEBUG(1) || DEBUG(2))
121874a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: Phase Mismatch sa=%.8lux\n",
121974a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun, sa);
122074a4d8c2SCharles.Forsyth 			/*
122174a4d8c2SCharles.Forsyth 			 * now recover
122274a4d8c2SCharles.Forsyth 			 */
122374a4d8c2SCharles.Forsyth 			if (sa == E_data_in_mismatch) {
122474a4d8c2SCharles.Forsyth 				dbc = read_mismatch_recover(c, n, dsa);
122574a4d8c2SCharles.Forsyth 				tbc = legetl(dsa->data_buf.dbc) - dbc;
122674a4d8c2SCharles.Forsyth 				advancedata(&dsa->data_buf, tbc);
122774a4d8c2SCharles.Forsyth 				if (DEBUG(1) || DEBUG(2))
122874a4d8c2SCharles.Forsyth 					IPRINT("sd53c8xx: %d/%d: transferred = %ld residue = %ld\n",
122974a4d8c2SCharles.Forsyth 					    dsa->target, dsa->lun, tbc, legetl(dsa->data_buf.dbc));
123074a4d8c2SCharles.Forsyth 				cont = E_to_decisions;
123174a4d8c2SCharles.Forsyth 			}
123274a4d8c2SCharles.Forsyth 			else if (sa == E_data_in_block_mismatch) {
123374a4d8c2SCharles.Forsyth 				dbc = read_mismatch_recover(c, n, dsa);
123474a4d8c2SCharles.Forsyth 				tbc = A_BSIZE - dbc;
123574a4d8c2SCharles.Forsyth 				/* recover current state from registers */
123674a4d8c2SCharles.Forsyth 				dmablks = n->scratcha[2];
123774a4d8c2SCharles.Forsyth 				dmaaddr = legetl(n->scratchb);
123874a4d8c2SCharles.Forsyth 				/* we have got to dmaaddr + tbc */
123974a4d8c2SCharles.Forsyth 				/* we have dmablks * A_BSIZE - tbc + residue left to do */
124074a4d8c2SCharles.Forsyth 				/* so remaining transfer is */
124174a4d8c2SCharles.Forsyth 				IPRINT("in_block_mismatch: dmaaddr = 0x%lux tbc=%lud dmablks=%d\n",
124274a4d8c2SCharles.Forsyth 				    dmaaddr, tbc, dmablks);
124374a4d8c2SCharles.Forsyth 				calcblockdma(dsa, dmaaddr + tbc,
124474a4d8c2SCharles.Forsyth 				    dmablks * A_BSIZE - tbc + legetl(dsa->data_buf.dbc));
124574a4d8c2SCharles.Forsyth 				/* copy changes into scratch registers */
124674a4d8c2SCharles.Forsyth 				IPRINT("recalc: dmablks %d dmaaddr 0x%lx pa 0x%lx dbc %ld\n",
124774a4d8c2SCharles.Forsyth 				    dsa->dmablks, legetl(dsa->dmaaddr),
124874a4d8c2SCharles.Forsyth 				    legetl(dsa->data_buf.pa), legetl(dsa->data_buf.dbc));
124974a4d8c2SCharles.Forsyth 				n->scratcha[2] = dsa->dmablks;
125074a4d8c2SCharles.Forsyth 				lesetl(n->scratchb, dsa->dmancr);
125174a4d8c2SCharles.Forsyth 				cont = E_data_block_mismatch_recover;
125274a4d8c2SCharles.Forsyth 			}
125374a4d8c2SCharles.Forsyth 			else if (sa == E_data_out_mismatch) {
125474a4d8c2SCharles.Forsyth 				dbc = write_mismatch_recover(n, dsa);
125574a4d8c2SCharles.Forsyth 				tbc = legetl(dsa->data_buf.dbc) - dbc;
125674a4d8c2SCharles.Forsyth 				advancedata(&dsa->data_buf, tbc);
125774a4d8c2SCharles.Forsyth 				if (DEBUG(1) || DEBUG(2))
125874a4d8c2SCharles.Forsyth 					IPRINT("sd53c8xx: %d/%d: transferred = %ld residue = %ld\n",
125974a4d8c2SCharles.Forsyth 					    dsa->target, dsa->lun, tbc, legetl(dsa->data_buf.dbc));
126074a4d8c2SCharles.Forsyth 				cont = E_to_decisions;
126174a4d8c2SCharles.Forsyth 			}
126274a4d8c2SCharles.Forsyth 			else if (sa == E_data_out_block_mismatch) {
126374a4d8c2SCharles.Forsyth 				dbc = write_mismatch_recover(n, dsa);
126474a4d8c2SCharles.Forsyth 				tbc = legetl(dsa->data_buf.dbc) - dbc;
126574a4d8c2SCharles.Forsyth 				/* recover current state from registers */
126674a4d8c2SCharles.Forsyth 				dmablks = n->scratcha[2];
126774a4d8c2SCharles.Forsyth 				dmaaddr = legetl(n->scratchb);
126874a4d8c2SCharles.Forsyth 				/* we have got to dmaaddr + tbc */
126974a4d8c2SCharles.Forsyth 				/* we have dmablks blocks - tbc + residue left to do */
127074a4d8c2SCharles.Forsyth 				/* so remaining transfer is */
127174a4d8c2SCharles.Forsyth 				IPRINT("out_block_mismatch: dmaaddr = %lux tbc=%lud dmablks=%d\n",
127274a4d8c2SCharles.Forsyth 				    dmaaddr, tbc, dmablks);
127374a4d8c2SCharles.Forsyth 				calcblockdma(dsa, dmaaddr + tbc,
127474a4d8c2SCharles.Forsyth 				    dmablks * A_BSIZE - tbc + legetl(dsa->data_buf.dbc));
127574a4d8c2SCharles.Forsyth 				/* copy changes into scratch registers */
127674a4d8c2SCharles.Forsyth 				n->scratcha[2] = dsa->dmablks;
127774a4d8c2SCharles.Forsyth 				lesetl(n->scratchb, dsa->dmancr);
127874a4d8c2SCharles.Forsyth 				cont = E_data_block_mismatch_recover;
127974a4d8c2SCharles.Forsyth 			}
128074a4d8c2SCharles.Forsyth 			else if (sa == E_id_out_mismatch) {
128174a4d8c2SCharles.Forsyth 				/*
128274a4d8c2SCharles.Forsyth 				 * target switched phases while attention held during
128374a4d8c2SCharles.Forsyth 				 * message out. The possibilities are:
128474a4d8c2SCharles.Forsyth 				 * 1. It didn't like the last message. This is indicated
128574a4d8c2SCharles.Forsyth 				 *    by the new phase being message_in. Use script to recover
128674a4d8c2SCharles.Forsyth 				 *
128774a4d8c2SCharles.Forsyth 				 * 2. It's not SCSI-II compliant. The new phase will be other
128874a4d8c2SCharles.Forsyth 				 *    than message_in. We should also indicate that the device
128974a4d8c2SCharles.Forsyth 				 *    is asynchronous, if it's the SDTR that got ignored
129074a4d8c2SCharles.Forsyth 				 *
129174a4d8c2SCharles.Forsyth 				 * For now, if the phase switch is not to message_in, and
129274a4d8c2SCharles.Forsyth 				 * and it happens after IDENTIFY and before SDTR, we
129374a4d8c2SCharles.Forsyth 				 * notify the negotiation state machine.
129474a4d8c2SCharles.Forsyth 				 */
129574a4d8c2SCharles.Forsyth 				ulong lim = legetl(dsa->msg_out_buf.dbc);
129674a4d8c2SCharles.Forsyth 				uchar p = n->sstat1 & 7;
129774a4d8c2SCharles.Forsyth 				dbc = write_mismatch_recover(n, dsa);
129874a4d8c2SCharles.Forsyth 				tbc = lim - dbc;
129974a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: msg_out_mismatch: %lud/%lud sent, phase %s\n",
130074a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun, tbc, lim, phase[p]);
130174a4d8c2SCharles.Forsyth 				if (p != MessageIn && tbc == 1) {
130274a4d8c2SCharles.Forsyth 					msgsm(dsa, c, A_SIR_EV_PHASE_SWITCH_AFTER_ID, &cont, &wakeme);
130374a4d8c2SCharles.Forsyth 				}
130474a4d8c2SCharles.Forsyth 				else
130574a4d8c2SCharles.Forsyth 					cont = E_id_out_mismatch_recover;
130674a4d8c2SCharles.Forsyth 			}
130774a4d8c2SCharles.Forsyth 			else if (sa == E_cmd_out_mismatch) {
130874a4d8c2SCharles.Forsyth 				/*
130974a4d8c2SCharles.Forsyth 				 * probably the command count is longer than the device wants ...
131074a4d8c2SCharles.Forsyth 				 */
131174a4d8c2SCharles.Forsyth 				ulong lim = legetl(dsa->cmd_buf.dbc);
131274a4d8c2SCharles.Forsyth 				uchar p = n->sstat1 & 7;
131374a4d8c2SCharles.Forsyth 				dbc = write_mismatch_recover(n, dsa);
131474a4d8c2SCharles.Forsyth 				tbc = lim - dbc;
131574a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: cmd_out_mismatch: %lud/%lud sent, phase %s\n",
131674a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun, tbc, lim, phase[p]);
131774a4d8c2SCharles.Forsyth 				USED(p, tbc);
131874a4d8c2SCharles.Forsyth 				cont = E_to_decisions;
131974a4d8c2SCharles.Forsyth 			}
132074a4d8c2SCharles.Forsyth 			else {
132174a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: ma sa=%.8lux wanted=%s got=%s\n",
132274a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun, sa,
132374a4d8c2SCharles.Forsyth 				    phase[n->dcmd & 7],
132474a4d8c2SCharles.Forsyth 				    phase[n->sstat1 & 7]);
132574a4d8c2SCharles.Forsyth 				dumpncrregs(c, 1);
132674a4d8c2SCharles.Forsyth 				dsa->p9status = SDeio;	/* chf */
132774a4d8c2SCharles.Forsyth 				wakeme = 1;
132874a4d8c2SCharles.Forsyth 			}
132974a4d8c2SCharles.Forsyth 		}
133074a4d8c2SCharles.Forsyth 		/*else*/ if (sist & 0x400) {
133174a4d8c2SCharles.Forsyth 			if (DEBUG(0))
133274a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d Sto\n", dsa->target, dsa->lun);
133374a4d8c2SCharles.Forsyth 			dsa->p9status = SDtimeout;
133474a4d8c2SCharles.Forsyth 			dsa->stateb = A_STATE_DONE;
133574a4d8c2SCharles.Forsyth 			softreset(c);
133674a4d8c2SCharles.Forsyth 			cont = E_issue_check;
133774a4d8c2SCharles.Forsyth 			wakeme = 1;
133874a4d8c2SCharles.Forsyth 		}
133974a4d8c2SCharles.Forsyth 		if (sist & 0x1) {
134074a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: %d/%d: parity error\n", dsa->target, dsa->lun);
134174a4d8c2SCharles.Forsyth 			dsa->parityerror = 1;
134274a4d8c2SCharles.Forsyth 		}
134374a4d8c2SCharles.Forsyth 		if (sist & 0x4) {
134474a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: %d/%d: unexpected disconnect\n",
134574a4d8c2SCharles.Forsyth 			    dsa->target, dsa->lun);
134674a4d8c2SCharles.Forsyth 			dumpncrregs(c, 1);
134774a4d8c2SCharles.Forsyth 			//wakeme = 1;
134874a4d8c2SCharles.Forsyth 			dsa->p9status = SDeio;
134974a4d8c2SCharles.Forsyth 		}
135074a4d8c2SCharles.Forsyth 	}
135174a4d8c2SCharles.Forsyth 	if (istat & Dip) {
135274a4d8c2SCharles.Forsyth 		if (DEBUG(1))
135374a4d8c2SCharles.Forsyth 			IPRINT("dstat = %.2x\n", dstat);
135474a4d8c2SCharles.Forsyth 		/*else*/ if (dstat & Ssi) {
135574a4d8c2SCharles.Forsyth 			ulong *p = DMASEG_TO_KADDR(legetl(n->dsp));
135674a4d8c2SCharles.Forsyth 			ulong w = (uchar *)p - (uchar *)c->script;
135774a4d8c2SCharles.Forsyth 			IPRINT("[%lux]", w);
135874a4d8c2SCharles.Forsyth 			USED(w);
135974a4d8c2SCharles.Forsyth 			cont = -2;	/* restart */
136074a4d8c2SCharles.Forsyth 		}
136174a4d8c2SCharles.Forsyth 		if (dstat & Sir) {
136274a4d8c2SCharles.Forsyth 			switch (legetl(n->dsps)) {
136374a4d8c2SCharles.Forsyth 			case A_SIR_MSG_IO_COMPLETE:
136474a4d8c2SCharles.Forsyth 				dsa->p9status = dsa->status;
136574a4d8c2SCharles.Forsyth 				wakeme = 1;
136674a4d8c2SCharles.Forsyth 				break;
136774a4d8c2SCharles.Forsyth 			case A_SIR_MSG_SDTR:
136874a4d8c2SCharles.Forsyth 			case A_SIR_MSG_WDTR:
136974a4d8c2SCharles.Forsyth 			case A_SIR_MSG_REJECT:
137074a4d8c2SCharles.Forsyth 			case A_SIR_EV_RESPONSE_OK:
137174a4d8c2SCharles.Forsyth 				msgsm(dsa, c, legetl(n->dsps), &cont, &wakeme);
137274a4d8c2SCharles.Forsyth 				break;
137374a4d8c2SCharles.Forsyth 			case A_SIR_MSG_IGNORE_WIDE_RESIDUE:
137474a4d8c2SCharles.Forsyth 				/* back up one in the data transfer */
137574a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: ignore wide residue %d, WSR = %d\n",
137674a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun, n->scratcha[1], n->scntl2 & 1);
137774a4d8c2SCharles.Forsyth 				if (dsa->dmablks == 0 && dsa->flag)
137874a4d8c2SCharles.Forsyth 					IPRINT("sd53c8xx: %d/%d: transfer over; residue ignored\n",
137974a4d8c2SCharles.Forsyth 					    dsa->target, dsa->lun);
138074a4d8c2SCharles.Forsyth 				else
138174a4d8c2SCharles.Forsyth 					calcblockdma(dsa, legetl(dsa->dmaaddr) - 1,
138274a4d8c2SCharles.Forsyth 					    dsa->dmablks * A_BSIZE + legetl(dsa->data_buf.dbc) + 1);
138374a4d8c2SCharles.Forsyth 				cont = -2;
138474a4d8c2SCharles.Forsyth 				break;
138574a4d8c2SCharles.Forsyth 			case A_SIR_ERROR_NOT_MSG_IN_AFTER_RESELECT:
138674a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d: not msg_in after reselect (%s)",
138774a4d8c2SCharles.Forsyth 				    n->ssid & 7, phase[n->sstat1 & 7]);
138874a4d8c2SCharles.Forsyth 				dsa = dsafind(c, n->ssid & 7, -1, A_STATE_DISCONNECTED);
138974a4d8c2SCharles.Forsyth 				dumpncrregs(c, 1);
139074a4d8c2SCharles.Forsyth 				wakeme = 1;
139174a4d8c2SCharles.Forsyth 				break;
139274a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_MSG_IN:
139374a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: msg_in %d\n",
139474a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun, n->sfbr);
139574a4d8c2SCharles.Forsyth 				cont = -2;
139674a4d8c2SCharles.Forsyth 				break;
139774a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_DISC:
139874a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: disconnect:", dsa->target, dsa->lun);
139974a4d8c2SCharles.Forsyth 				goto dsadump;
140074a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_STATUS:
140174a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: status\n", dsa->target, dsa->lun);
140274a4d8c2SCharles.Forsyth 				cont = -2;
140374a4d8c2SCharles.Forsyth 				break;
140474a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_COMMAND:
140574a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: commands\n", dsa->target, dsa->lun);
140674a4d8c2SCharles.Forsyth 				cont = -2;
140774a4d8c2SCharles.Forsyth 				break;
140874a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_DATA_IN:
140974a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: data in a %lx b %lx\n",
141074a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun, legetl(n->scratcha), legetl(n->scratchb));
141174a4d8c2SCharles.Forsyth 				cont = -2;
141274a4d8c2SCharles.Forsyth 				break;
141374a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_BLOCK_DATA_IN:
141474a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: block data in: a2 %x b %lx\n",
141574a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun, n->scratcha[2], legetl(n->scratchb));
141674a4d8c2SCharles.Forsyth 				cont = -2;
141774a4d8c2SCharles.Forsyth 				break;
141874a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_DATA_OUT:
141974a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: data out\n", dsa->target, dsa->lun);
142074a4d8c2SCharles.Forsyth 				cont = -2;
142174a4d8c2SCharles.Forsyth 				break;
142274a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_DUMP:
142374a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: dump\n", dsa->target, dsa->lun);
142474a4d8c2SCharles.Forsyth 				dumpncrregs(c, 1);
142574a4d8c2SCharles.Forsyth 				cont = -2;
142674a4d8c2SCharles.Forsyth 				break;
142774a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_DUMP2:
142874a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: dump2:", dsa->target, dsa->lun);
142974a4d8c2SCharles.Forsyth 				IPRINT(" sa %lux", legetl(n->dsp) - c->scriptpa);
143074a4d8c2SCharles.Forsyth 				IPRINT(" dsa %lux", legetl(n->dsa));
143174a4d8c2SCharles.Forsyth 				IPRINT(" sfbr %ux", n->sfbr);
143274a4d8c2SCharles.Forsyth 				IPRINT(" a %lux", n->scratcha);
143374a4d8c2SCharles.Forsyth 				IPRINT(" b %lux", legetl(n->scratchb));
143474a4d8c2SCharles.Forsyth 				IPRINT(" ssid %ux", n->ssid);
143574a4d8c2SCharles.Forsyth 				IPRINT("\n");
143674a4d8c2SCharles.Forsyth 				cont = -2;
143774a4d8c2SCharles.Forsyth 				break;
143874a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_WAIT_RESELECT:
143974a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: wait reselect\n");
144074a4d8c2SCharles.Forsyth 				cont = -2;
144174a4d8c2SCharles.Forsyth 				break;
144274a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_RESELECT:
144374a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: reselect: ssid %.2x sfbr %.2x at %ld\n",
144474a4d8c2SCharles.Forsyth 				    n->ssid, n->sfbr, TK2MS(m->ticks));
144574a4d8c2SCharles.Forsyth 				cont = -2;
144674a4d8c2SCharles.Forsyth 				break;
144774a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_ISSUE:
144874a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: issue:", dsa->target, dsa->lun);
144974a4d8c2SCharles.Forsyth 			dsadump:
145074a4d8c2SCharles.Forsyth 				IPRINT(" tgt=%d", dsa->target);
145174a4d8c2SCharles.Forsyth 				IPRINT(" time=%ld", TK2MS(m->ticks));
145274a4d8c2SCharles.Forsyth 				IPRINT("\n");
145374a4d8c2SCharles.Forsyth 				cont = -2;
145474a4d8c2SCharles.Forsyth 				break;
145574a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_ISSUE_CHECK:
145674a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: issue check\n");
145774a4d8c2SCharles.Forsyth 				cont = -2;
145874a4d8c2SCharles.Forsyth 				break;
145974a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_SIGP:
146074a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: responded to SIGP\n");
146174a4d8c2SCharles.Forsyth 				cont = -2;
146274a4d8c2SCharles.Forsyth 				break;
146374a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_DUMP_NEXT_CODE: {
146474a4d8c2SCharles.Forsyth 				ulong *dsp = DMASEG_TO_KADDR(legetl(n->dsp));
146574a4d8c2SCharles.Forsyth 				int x;
146674a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: code at %lux", dsp - c->script);
146774a4d8c2SCharles.Forsyth 				for (x = 0; x < 6; x++)
146874a4d8c2SCharles.Forsyth 					IPRINT(" %.8lux", dsp[x]);
146974a4d8c2SCharles.Forsyth 				IPRINT("\n");
147074a4d8c2SCharles.Forsyth 				USED(dsp);
147174a4d8c2SCharles.Forsyth 				cont = -2;
147274a4d8c2SCharles.Forsyth 				break;
147374a4d8c2SCharles.Forsyth 			}
147474a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_WSR:
147574a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: WSR set\n", dsa->target, dsa->lun);
147674a4d8c2SCharles.Forsyth 				cont = -2;
147774a4d8c2SCharles.Forsyth 				break;
147874a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_LOAD_SYNC:
147974a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: scntl=%.2x sxfer=%.2x\n",
148074a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun, n->scntl3, n->sxfer);
148174a4d8c2SCharles.Forsyth 				cont = -2;
148274a4d8c2SCharles.Forsyth 				break;
148374a4d8c2SCharles.Forsyth 			case A_SIR_NOTIFY_RESELECTED_ON_SELECT:
148474a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: reselected during select\n",
148574a4d8c2SCharles.Forsyth 				    dsa->target, dsa->lun);
148674a4d8c2SCharles.Forsyth 				cont = -2;
148774a4d8c2SCharles.Forsyth 				break;
148874a4d8c2SCharles.Forsyth 			default:
148974a4d8c2SCharles.Forsyth 				IPRINT("sd53c8xx: %d/%d: script error %ld\n",
149074a4d8c2SCharles.Forsyth 					dsa->target, dsa->lun, legetl(n->dsps));
149174a4d8c2SCharles.Forsyth 				dumpncrregs(c, 1);
149274a4d8c2SCharles.Forsyth 				wakeme = 1;
149374a4d8c2SCharles.Forsyth 			}
149474a4d8c2SCharles.Forsyth 		}
149574a4d8c2SCharles.Forsyth 		/*else*/ if (dstat & Iid) {
149674a4d8c2SCharles.Forsyth 			ulong addr = legetl(n->dsp);
149774a4d8c2SCharles.Forsyth 			ulong dbc = (n->dbc[2]<<16)|(n->dbc[1]<<8)|n->dbc[0];
149874a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: %d/%d: Iid pa=%.8lux sa=%.8lux dbc=%lux\n",
149974a4d8c2SCharles.Forsyth 			    dsa->target, dsa->lun,
150074a4d8c2SCharles.Forsyth 			    addr, addr - c->scriptpa, dbc);
150174a4d8c2SCharles.Forsyth 			addr = (ulong)DMASEG_TO_KADDR(addr);
150274a4d8c2SCharles.Forsyth 			IPRINT("%.8lux %.8lux %.8lux\n",
150374a4d8c2SCharles.Forsyth 			    *(ulong *)(addr - 12), *(ulong *)(addr - 8), *(ulong *)(addr - 4));
150474a4d8c2SCharles.Forsyth 			USED(addr, dbc);
150574a4d8c2SCharles.Forsyth 			dsa->p9status = SDeio;
150674a4d8c2SCharles.Forsyth 			wakeme = 1;
150774a4d8c2SCharles.Forsyth 		}
150874a4d8c2SCharles.Forsyth 		/*else*/ if (dstat & Bf) {
150974a4d8c2SCharles.Forsyth 			IPRINT("sd53c8xx: %d/%d: Bus Fault\n", dsa->target, dsa->lun);
151074a4d8c2SCharles.Forsyth 			dumpncrregs(c, 1);
151174a4d8c2SCharles.Forsyth 			dsa->p9status = SDeio;
151274a4d8c2SCharles.Forsyth 			wakeme = 1;
151374a4d8c2SCharles.Forsyth 		}
151474a4d8c2SCharles.Forsyth 	}
151574a4d8c2SCharles.Forsyth 	if (cont == -2)
151674a4d8c2SCharles.Forsyth 		ncrcontinue(c);
151774a4d8c2SCharles.Forsyth 	else if (cont >= 0)
151874a4d8c2SCharles.Forsyth 		start(c, cont);
151974a4d8c2SCharles.Forsyth 	if (wakeme){
152074a4d8c2SCharles.Forsyth 		if(dsa->p9status == SDnostatus)
152174a4d8c2SCharles.Forsyth 			dsa->p9status = SDeio;
152274a4d8c2SCharles.Forsyth 		wakeup(dsa);
152374a4d8c2SCharles.Forsyth 	}
152474a4d8c2SCharles.Forsyth 	iunlock(c);
152574a4d8c2SCharles.Forsyth 	if (DEBUG(1)) {
152674a4d8c2SCharles.Forsyth 		IPRINT("sd53c8xx: int end 1\n");
152774a4d8c2SCharles.Forsyth 	}
152874a4d8c2SCharles.Forsyth }
152974a4d8c2SCharles.Forsyth 
153074a4d8c2SCharles.Forsyth static int
done(void * arg)153174a4d8c2SCharles.Forsyth done(void *arg)
153274a4d8c2SCharles.Forsyth {
153374a4d8c2SCharles.Forsyth 	return ((Dsa *)arg)->p9status != SDnostatus;
153474a4d8c2SCharles.Forsyth }
153574a4d8c2SCharles.Forsyth 
153674a4d8c2SCharles.Forsyth static void
setmovedata(Movedata * d,ulong pa,ulong bc)153774a4d8c2SCharles.Forsyth setmovedata(Movedata *d, ulong pa, ulong bc)
153874a4d8c2SCharles.Forsyth {
153974a4d8c2SCharles.Forsyth 	d->pa[0] = pa;
154074a4d8c2SCharles.Forsyth 	d->pa[1] = pa>>8;
154174a4d8c2SCharles.Forsyth 	d->pa[2] = pa>>16;
154274a4d8c2SCharles.Forsyth 	d->pa[3] = pa>>24;
154374a4d8c2SCharles.Forsyth 	d->dbc[0] = bc;
154474a4d8c2SCharles.Forsyth 	d->dbc[1] = bc>>8;
154574a4d8c2SCharles.Forsyth 	d->dbc[2] = bc>>16;
154674a4d8c2SCharles.Forsyth 	d->dbc[3] = bc>>24;
154774a4d8c2SCharles.Forsyth }
154874a4d8c2SCharles.Forsyth 
154974a4d8c2SCharles.Forsyth static void
advancedata(Movedata * d,long v)155074a4d8c2SCharles.Forsyth advancedata(Movedata *d, long v)
155174a4d8c2SCharles.Forsyth {
155274a4d8c2SCharles.Forsyth 	lesetl(d->pa, legetl(d->pa) + v);
155374a4d8c2SCharles.Forsyth 	lesetl(d->dbc, legetl(d->dbc) - v);
155474a4d8c2SCharles.Forsyth }
155574a4d8c2SCharles.Forsyth 
155674a4d8c2SCharles.Forsyth static void
dumpwritedata(uchar * data,int datalen)155774a4d8c2SCharles.Forsyth dumpwritedata(uchar *data, int datalen)
155874a4d8c2SCharles.Forsyth {
155974a4d8c2SCharles.Forsyth 	int i;
156074a4d8c2SCharles.Forsyth 	uchar *bp;
156174a4d8c2SCharles.Forsyth 	if (!DEBUG(0)){
156274a4d8c2SCharles.Forsyth 		USED(data, datalen);
156374a4d8c2SCharles.Forsyth 		return;
156474a4d8c2SCharles.Forsyth 	}
156574a4d8c2SCharles.Forsyth 
156674a4d8c2SCharles.Forsyth 	if (datalen) {
156774a4d8c2SCharles.Forsyth 		KPRINT("sd53c8xx:write:");
156874a4d8c2SCharles.Forsyth 		for (i = 0, bp = data; i < 50 && i < datalen; i++, bp++)
156974a4d8c2SCharles.Forsyth 			KPRINT("%.2ux", *bp);
157074a4d8c2SCharles.Forsyth 		if (i < datalen) {
157174a4d8c2SCharles.Forsyth 			KPRINT("...");
157274a4d8c2SCharles.Forsyth 		}
157374a4d8c2SCharles.Forsyth 		KPRINT("\n");
157474a4d8c2SCharles.Forsyth 	}
157574a4d8c2SCharles.Forsyth }
157674a4d8c2SCharles.Forsyth 
157774a4d8c2SCharles.Forsyth static void
dumpreaddata(uchar * data,int datalen)157874a4d8c2SCharles.Forsyth dumpreaddata(uchar *data, int datalen)
157974a4d8c2SCharles.Forsyth {
158074a4d8c2SCharles.Forsyth 	int i;
158174a4d8c2SCharles.Forsyth 	uchar *bp;
158274a4d8c2SCharles.Forsyth 	if (!DEBUG(0)){
158374a4d8c2SCharles.Forsyth 		USED(data, datalen);
158474a4d8c2SCharles.Forsyth 		return;
158574a4d8c2SCharles.Forsyth 	}
158674a4d8c2SCharles.Forsyth 
158774a4d8c2SCharles.Forsyth 	if (datalen) {
158874a4d8c2SCharles.Forsyth 		KPRINT("sd53c8xx:read:");
158974a4d8c2SCharles.Forsyth 		for (i = 0, bp = data; i < 50 && i < datalen; i++, bp++)
159074a4d8c2SCharles.Forsyth 			KPRINT("%.2ux", *bp);
159174a4d8c2SCharles.Forsyth 		if (i < datalen) {
159274a4d8c2SCharles.Forsyth 			KPRINT("...");
159374a4d8c2SCharles.Forsyth 		}
159474a4d8c2SCharles.Forsyth 		KPRINT("\n");
159574a4d8c2SCharles.Forsyth 	}
159674a4d8c2SCharles.Forsyth }
159774a4d8c2SCharles.Forsyth 
159874a4d8c2SCharles.Forsyth static void
busreset(Controller * c)159974a4d8c2SCharles.Forsyth busreset(Controller *c)
160074a4d8c2SCharles.Forsyth {
160174a4d8c2SCharles.Forsyth 	int x, ntarget;
160274a4d8c2SCharles.Forsyth 
160374a4d8c2SCharles.Forsyth 	/* bus reset */
160474a4d8c2SCharles.Forsyth 	c->n->scntl1 |= (1 << 3);
160574a4d8c2SCharles.Forsyth 	delay(500);
160674a4d8c2SCharles.Forsyth 	c->n->scntl1 &= ~(1 << 3);
160774a4d8c2SCharles.Forsyth 	if(!(c->v->feature & Wide))
160874a4d8c2SCharles.Forsyth 		ntarget = 8;
160974a4d8c2SCharles.Forsyth 	else
161074a4d8c2SCharles.Forsyth 		ntarget = MAXTARGET;
161174a4d8c2SCharles.Forsyth 	for (x = 0; x < ntarget; x++) {
161274a4d8c2SCharles.Forsyth 		setwide(0, c, x, 0);
161374a4d8c2SCharles.Forsyth #ifndef ASYNC_ONLY
161474a4d8c2SCharles.Forsyth 		c->s[x] = NeitherDone;
161574a4d8c2SCharles.Forsyth #endif
161674a4d8c2SCharles.Forsyth 	}
161774a4d8c2SCharles.Forsyth 	c->capvalid = 0;
161874a4d8c2SCharles.Forsyth }
161974a4d8c2SCharles.Forsyth 
162074a4d8c2SCharles.Forsyth static void
reset(Controller * c)162174a4d8c2SCharles.Forsyth reset(Controller *c)
162274a4d8c2SCharles.Forsyth {
162374a4d8c2SCharles.Forsyth 	/* should wakeup all pending tasks */
162474a4d8c2SCharles.Forsyth 	softreset(c);
162574a4d8c2SCharles.Forsyth 	busreset(c);
162674a4d8c2SCharles.Forsyth }
162774a4d8c2SCharles.Forsyth 
162874a4d8c2SCharles.Forsyth static int
symrio(SDreq * r)162974a4d8c2SCharles.Forsyth symrio(SDreq* r)
163074a4d8c2SCharles.Forsyth {
163174a4d8c2SCharles.Forsyth 	Dsa *d;
163274a4d8c2SCharles.Forsyth 	uchar *bp;
163374a4d8c2SCharles.Forsyth 	Controller *c;
163474a4d8c2SCharles.Forsyth 	uchar target_expo, my_expo;
163574a4d8c2SCharles.Forsyth 	int bc, check, status, target;
163674a4d8c2SCharles.Forsyth 
163774a4d8c2SCharles.Forsyth 	if((target = r->unit->subno) == 0x07)
163874a4d8c2SCharles.Forsyth 		return r->status = SDtimeout;	/* assign */
163974a4d8c2SCharles.Forsyth 	c = r->unit->dev->ctlr;
164074a4d8c2SCharles.Forsyth 
164174a4d8c2SCharles.Forsyth 	check = 0;
164274a4d8c2SCharles.Forsyth 	d = dsaalloc(c, target, r->lun);
164374a4d8c2SCharles.Forsyth 
164474a4d8c2SCharles.Forsyth 	qlock(&c->q[target]);			/* obtain access to target */
164574a4d8c2SCharles.Forsyth docheck:
164674a4d8c2SCharles.Forsyth 	/* load the transfer control stuff */
164774a4d8c2SCharles.Forsyth 	d->scsi_id_buf[0] = 0;
164874a4d8c2SCharles.Forsyth 	d->scsi_id_buf[1] = c->sxfer[target];
164974a4d8c2SCharles.Forsyth 	d->scsi_id_buf[2] = target;
165074a4d8c2SCharles.Forsyth 	d->scsi_id_buf[3] = c->scntl3[target];
165174a4d8c2SCharles.Forsyth 	synctodsa(d, c);
165274a4d8c2SCharles.Forsyth 
165374a4d8c2SCharles.Forsyth 	bc = 0;
165474a4d8c2SCharles.Forsyth 
165574a4d8c2SCharles.Forsyth 	d->msg_out[bc] = 0x80 | r->lun;
165674a4d8c2SCharles.Forsyth 
165774a4d8c2SCharles.Forsyth #ifndef NO_DISCONNECT
165874a4d8c2SCharles.Forsyth 	d->msg_out[bc] |= (1 << 6);
165974a4d8c2SCharles.Forsyth #endif
166074a4d8c2SCharles.Forsyth 	bc++;
166174a4d8c2SCharles.Forsyth 
166274a4d8c2SCharles.Forsyth 	/* work out what to do about negotiation */
166374a4d8c2SCharles.Forsyth 	switch (c->s[target]) {
166474a4d8c2SCharles.Forsyth 	default:
166574a4d8c2SCharles.Forsyth 		KPRINT("sd53c8xx: %d: strange nego state %d\n", target, c->s[target]);
166674a4d8c2SCharles.Forsyth 		c->s[target] = NeitherDone;
166774a4d8c2SCharles.Forsyth 		/* fall through */
166874a4d8c2SCharles.Forsyth 	case NeitherDone:
166974a4d8c2SCharles.Forsyth 		if ((c->capvalid & (1 << target)) == 0)
167074a4d8c2SCharles.Forsyth 			break;
167174a4d8c2SCharles.Forsyth 		target_expo = (c->cap[target] >> 5) & 3;
167274a4d8c2SCharles.Forsyth 		my_expo = (c->v->feature & Wide) != 0;
167374a4d8c2SCharles.Forsyth 		if (target_expo < my_expo)
167474a4d8c2SCharles.Forsyth 			my_expo = target_expo;
167574a4d8c2SCharles.Forsyth #ifdef ALWAYS_DO_WDTR
167674a4d8c2SCharles.Forsyth 		bc += buildwdtrmsg(d->msg_out + bc, my_expo);
167774a4d8c2SCharles.Forsyth 		KPRINT("sd53c8xx: %d: WDTN: initiating expo %d\n", target, my_expo);
167874a4d8c2SCharles.Forsyth 		c->s[target] = WideInit;
167974a4d8c2SCharles.Forsyth 		break;
168074a4d8c2SCharles.Forsyth #else
168174a4d8c2SCharles.Forsyth 		if (my_expo) {
168274a4d8c2SCharles.Forsyth 			bc += buildwdtrmsg(d->msg_out + bc, (c->v->feature & Wide) ? 1 : 0);
168374a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: WDTN: initiating expo %d\n", target, my_expo);
168474a4d8c2SCharles.Forsyth 			c->s[target] = WideInit;
168574a4d8c2SCharles.Forsyth 			break;
168674a4d8c2SCharles.Forsyth 		}
168774a4d8c2SCharles.Forsyth 		KPRINT("sd53c8xx: %d: WDTN: narrow\n", target);
168874a4d8c2SCharles.Forsyth 		/* fall through */
168974a4d8c2SCharles.Forsyth #endif
169074a4d8c2SCharles.Forsyth 	case WideDone:
169174a4d8c2SCharles.Forsyth 		if (c->cap[target] & (1 << 4)) {
169274a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d: SDTN: initiating %d %d\n", target, c->tpf, c->v->maxsyncoff);
169374a4d8c2SCharles.Forsyth 			bc += buildsdtrmsg(d->msg_out + bc, c->tpf, c->v->maxsyncoff);
169474a4d8c2SCharles.Forsyth 			c->s[target] = SyncInit;
169574a4d8c2SCharles.Forsyth 			break;
169674a4d8c2SCharles.Forsyth 		}
169774a4d8c2SCharles.Forsyth 		KPRINT("sd53c8xx: %d: SDTN: async only\n", target);
169874a4d8c2SCharles.Forsyth 		c->s[target] = BothDone;
169974a4d8c2SCharles.Forsyth 		break;
170074a4d8c2SCharles.Forsyth 
170174a4d8c2SCharles.Forsyth 	case BothDone:
170274a4d8c2SCharles.Forsyth 		break;
170374a4d8c2SCharles.Forsyth 	}
170474a4d8c2SCharles.Forsyth 
170574a4d8c2SCharles.Forsyth 	setmovedata(&d->msg_out_buf, DMASEG(d->msg_out), bc);
170674a4d8c2SCharles.Forsyth 	setmovedata(&d->cmd_buf, DMASEG(r->cmd), r->clen);
170774a4d8c2SCharles.Forsyth 	calcblockdma(d, DMASEG(r->data), r->dlen);
170874a4d8c2SCharles.Forsyth 
170974a4d8c2SCharles.Forsyth 	if (DEBUG(0)) {
171074a4d8c2SCharles.Forsyth 		KPRINT("sd53c8xx: %d/%d: exec: ", target, r->lun);
171174a4d8c2SCharles.Forsyth 		for (bp = r->cmd; bp < &r->cmd[r->clen]; bp++)
171274a4d8c2SCharles.Forsyth 			KPRINT("%.2ux", *bp);
171374a4d8c2SCharles.Forsyth 		KPRINT("\n");
171474a4d8c2SCharles.Forsyth 		if (!r->write)
171574a4d8c2SCharles.Forsyth 			KPRINT("sd53c8xx: %d/%d: exec: limit=(%d)%ld\n",
171674a4d8c2SCharles.Forsyth 			  target, r->lun, d->dmablks, legetl(d->data_buf.dbc));
171774a4d8c2SCharles.Forsyth 		else
171874a4d8c2SCharles.Forsyth 			dumpwritedata(r->data, r->dlen);
171974a4d8c2SCharles.Forsyth 	}
172074a4d8c2SCharles.Forsyth 
172174a4d8c2SCharles.Forsyth 	setmovedata(&d->status_buf, DMASEG(&d->status), 1);
172274a4d8c2SCharles.Forsyth 
172374a4d8c2SCharles.Forsyth 	d->p9status = SDnostatus;
172474a4d8c2SCharles.Forsyth 	d->parityerror = 0;
172574a4d8c2SCharles.Forsyth 
172674a4d8c2SCharles.Forsyth 	d->stateb = A_STATE_ISSUE;		/* start operation */
172774a4d8c2SCharles.Forsyth 
172874a4d8c2SCharles.Forsyth 	ilock(c);
172974a4d8c2SCharles.Forsyth 	if (c->ssm)
173074a4d8c2SCharles.Forsyth 		c->n->dcntl |= 0x10;		/* SSI */
173174a4d8c2SCharles.Forsyth 	if (c->running) {
173274a4d8c2SCharles.Forsyth 		c->n->istat |= Sigp;
173374a4d8c2SCharles.Forsyth 	}
173474a4d8c2SCharles.Forsyth 	else {
173574a4d8c2SCharles.Forsyth 		start(c, E_issue_check);
173674a4d8c2SCharles.Forsyth 	}
173774a4d8c2SCharles.Forsyth 	iunlock(c);
173874a4d8c2SCharles.Forsyth 
173974a4d8c2SCharles.Forsyth 	while(waserror())
174074a4d8c2SCharles.Forsyth 		;
174174a4d8c2SCharles.Forsyth 	tsleep(d, done, d, 30 * 1000);
174274a4d8c2SCharles.Forsyth 	poperror();
174374a4d8c2SCharles.Forsyth 
174474a4d8c2SCharles.Forsyth 	if (!done(d)) {
174574a4d8c2SCharles.Forsyth 		KPRINT("sd53c8xx: %d/%d: exec: Timed out\n", target, r->lun);
174674a4d8c2SCharles.Forsyth 		dumpncrregs(c, 0);
174774a4d8c2SCharles.Forsyth 		dsafree(c, d);
174874a4d8c2SCharles.Forsyth 		reset(c);
174974a4d8c2SCharles.Forsyth 		qunlock(&c->q[target]);
175074a4d8c2SCharles.Forsyth 		r->status = SDtimeout;
175174a4d8c2SCharles.Forsyth 		return r->status = SDtimeout;	/* assign */
175274a4d8c2SCharles.Forsyth 	}
175374a4d8c2SCharles.Forsyth 
175474a4d8c2SCharles.Forsyth 	if((status = d->p9status) == SDeio)
175574a4d8c2SCharles.Forsyth 		c->s[target] = NeitherDone;
175674a4d8c2SCharles.Forsyth 	if (d->parityerror) {
175774a4d8c2SCharles.Forsyth 		status = SDeio;
175874a4d8c2SCharles.Forsyth 	}
175974a4d8c2SCharles.Forsyth 
176074a4d8c2SCharles.Forsyth 	/*
176174a4d8c2SCharles.Forsyth 	 * adjust datalen
176274a4d8c2SCharles.Forsyth 	 */
176374a4d8c2SCharles.Forsyth 	r->rlen = r->dlen;
176474a4d8c2SCharles.Forsyth 	if (d->dmablks > 0)
176574a4d8c2SCharles.Forsyth 		r->rlen -= d->dmablks * A_BSIZE;
176674a4d8c2SCharles.Forsyth 	else if (d->flag == 0)
176774a4d8c2SCharles.Forsyth 		r->rlen -= legetl(d->data_buf.dbc);
176874a4d8c2SCharles.Forsyth 	if(!r->write)
176974a4d8c2SCharles.Forsyth 		dumpreaddata(r->data, r->rlen);
177074a4d8c2SCharles.Forsyth 	if (DEBUG(0))
177174a4d8c2SCharles.Forsyth 		KPRINT("53c8xx: %d/%d: exec: p9status=%d status %d rlen %ld\n",
177274a4d8c2SCharles.Forsyth 		    target, r->lun, d->p9status, status, r->rlen);
177374a4d8c2SCharles.Forsyth 	/*
177474a4d8c2SCharles.Forsyth 	 * spot the identify
177574a4d8c2SCharles.Forsyth 	 */
177674a4d8c2SCharles.Forsyth 	if ((c->capvalid & (1 << target)) == 0
177774a4d8c2SCharles.Forsyth 	 && (status == SDok || status == SDcheck)
177874a4d8c2SCharles.Forsyth 	 && r->cmd[0] == 0x12 && r->dlen >= 8) {
177974a4d8c2SCharles.Forsyth 		c->capvalid |= 1 << target;
178074a4d8c2SCharles.Forsyth 		bp = r->data;
178174a4d8c2SCharles.Forsyth 		c->cap[target] = bp[7];
178274a4d8c2SCharles.Forsyth 		KPRINT("sd53c8xx: %d: capabilities %.2x\n", target, bp[7]);
178374a4d8c2SCharles.Forsyth 	}
178474a4d8c2SCharles.Forsyth 	if(!check && status == SDcheck && !(r->flags & SDnosense)){
178574a4d8c2SCharles.Forsyth 		check = 1;
178674a4d8c2SCharles.Forsyth 		r->write = 0;
178774a4d8c2SCharles.Forsyth 		memset(r->cmd, 0, sizeof(r->cmd));
178874a4d8c2SCharles.Forsyth 		r->cmd[0] = 0x03;
178974a4d8c2SCharles.Forsyth 		r->cmd[1] = r->lun<<5;
179074a4d8c2SCharles.Forsyth 		r->cmd[4] = sizeof(r->sense)-1;
179174a4d8c2SCharles.Forsyth 		r->clen = 6;
179274a4d8c2SCharles.Forsyth 		r->data = r->sense;
179374a4d8c2SCharles.Forsyth 		r->dlen = sizeof(r->sense)-1;
179474a4d8c2SCharles.Forsyth 		/*
179574a4d8c2SCharles.Forsyth 		 * Clear out the microcode state
179674a4d8c2SCharles.Forsyth 		 * so the Dsa can be re-used.
179774a4d8c2SCharles.Forsyth 		 */
179874a4d8c2SCharles.Forsyth 		lesetl(d->state, A_STATE_ALLOCATED);
179974a4d8c2SCharles.Forsyth 		goto docheck;
180074a4d8c2SCharles.Forsyth 	}
180174a4d8c2SCharles.Forsyth 	qunlock(&c->q[target]);
180274a4d8c2SCharles.Forsyth 	dsafree(c, d);
180374a4d8c2SCharles.Forsyth 
180474a4d8c2SCharles.Forsyth 	if(status == SDok && check){
180574a4d8c2SCharles.Forsyth 		status = SDcheck;
180674a4d8c2SCharles.Forsyth 		r->flags |= SDvalidsense;
180774a4d8c2SCharles.Forsyth 	}
180874a4d8c2SCharles.Forsyth 	KPRINT("sd53c8xx: %d: r flags %8.8uX status %d rlen %ld\n",
180974a4d8c2SCharles.Forsyth 		target, r->flags, status, r->rlen);
181074a4d8c2SCharles.Forsyth 	return r->status = status;
181174a4d8c2SCharles.Forsyth }
181274a4d8c2SCharles.Forsyth 
181374a4d8c2SCharles.Forsyth static void
cribbios(Controller * c)181474a4d8c2SCharles.Forsyth cribbios(Controller *c)
181574a4d8c2SCharles.Forsyth {
181674a4d8c2SCharles.Forsyth 	c->bios.scntl3 = c->n->scntl3;
181774a4d8c2SCharles.Forsyth 	c->bios.stest2 = c->n->stest2;
181874a4d8c2SCharles.Forsyth 	print("sd53c8xx: bios scntl3(%.2x) stest2(%.2x)\n", c->bios.scntl3, c->bios.stest2);
181974a4d8c2SCharles.Forsyth }
182074a4d8c2SCharles.Forsyth 
182174a4d8c2SCharles.Forsyth static int
bios_set_differential(Controller * c)182274a4d8c2SCharles.Forsyth bios_set_differential(Controller *c)
182374a4d8c2SCharles.Forsyth {
182474a4d8c2SCharles.Forsyth 	/* Concept lifted from FreeBSD - thanks Gerard */
182574a4d8c2SCharles.Forsyth 	/* basically, if clock conversion factors are set, then there is
182674a4d8c2SCharles.Forsyth  	 * evidence the bios had a go at the chip, and if so, it would
182774a4d8c2SCharles.Forsyth 	 * have set the differential enable bit in stest2
182874a4d8c2SCharles.Forsyth 	 */
182974a4d8c2SCharles.Forsyth 	return (c->bios.scntl3 & 7) != 0 && (c->bios.stest2 & 0x20) != 0;
183074a4d8c2SCharles.Forsyth }
183174a4d8c2SCharles.Forsyth 
183274a4d8c2SCharles.Forsyth #define NCR_VID 	0x1000
183374a4d8c2SCharles.Forsyth #define NCR_810_DID 	0x0001
183474a4d8c2SCharles.Forsyth #define NCR_820_DID	0x0002	/* don't know enough about this one to support it */
183574a4d8c2SCharles.Forsyth #define NCR_825_DID	0x0003
183674a4d8c2SCharles.Forsyth #define NCR_815_DID	0x0004
183774a4d8c2SCharles.Forsyth #define SYM_810AP_DID	0x0005
183874a4d8c2SCharles.Forsyth #define SYM_860_DID	0x0006
183974a4d8c2SCharles.Forsyth #define SYM_896_DID	0x000b
184074a4d8c2SCharles.Forsyth #define SYM_895_DID	0x000c
184174a4d8c2SCharles.Forsyth #define SYM_885_DID	0x000d	/* ditto */
184274a4d8c2SCharles.Forsyth #define SYM_875_DID	0x000f	/* ditto */
184374a4d8c2SCharles.Forsyth #define SYM_1010_DID	0x0020
184474a4d8c2SCharles.Forsyth #define SYM_1011_DID	0x0021
184574a4d8c2SCharles.Forsyth #define SYM_875J_DID	0x008f
184674a4d8c2SCharles.Forsyth 
184774a4d8c2SCharles.Forsyth static Variant variant[] = {
184874a4d8c2SCharles.Forsyth { NCR_810_DID,   0x0f, "NCR53C810",	Burst16,   8, 24, 0 },
184974a4d8c2SCharles.Forsyth { NCR_810_DID,   0x1f, "SYM53C810ALV",	Burst16,   8, 24, Prefetch },
185074a4d8c2SCharles.Forsyth { NCR_810_DID,   0xff, "SYM53C810A",	Burst16,   8, 24, Prefetch },
185174a4d8c2SCharles.Forsyth { SYM_810AP_DID, 0xff, "SYM53C810AP",	Burst16,   8, 24, Prefetch },
185274a4d8c2SCharles.Forsyth { NCR_815_DID,   0xff, "NCR53C815",	Burst16,   8, 24, BurstOpCodeFetch },
185374a4d8c2SCharles.Forsyth { NCR_825_DID,   0x0f, "NCR53C825",	Burst16,   8, 24, Wide|BurstOpCodeFetch|Differential },
185474a4d8c2SCharles.Forsyth { NCR_825_DID,   0xff, "SYM53C825A",	Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Differential|Wide },
185574a4d8c2SCharles.Forsyth { SYM_860_DID,   0x0f, "SYM53C860",	Burst16,   8, 24, Prefetch|Ultra },
185674a4d8c2SCharles.Forsyth { SYM_860_DID,   0xff, "SYM53C860LV",	Burst16,   8, 24, Prefetch|Ultra },
185774a4d8c2SCharles.Forsyth { SYM_875_DID,   0x01, "SYM53C875r1",	Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Differential|Wide|Ultra },
185874a4d8c2SCharles.Forsyth { SYM_875_DID,   0xff, "SYM53C875",	Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Differential|Wide|Ultra|ClockDouble },
185974a4d8c2SCharles.Forsyth { SYM_875J_DID,   0xff, "SYM53C875j",	Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Differential|Wide|Ultra|ClockDouble },
186074a4d8c2SCharles.Forsyth { SYM_885_DID,   0xff, "SYM53C885",	Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Wide|Ultra|ClockDouble },
186174a4d8c2SCharles.Forsyth { SYM_895_DID,   0xff, "SYM53C895",	Burst128, 16, 24, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
186274a4d8c2SCharles.Forsyth { SYM_896_DID,   0xff, "SYM53C896",	Burst128, 16, 64, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
186374a4d8c2SCharles.Forsyth { SYM_1010_DID,   0xff, "SYM53C1010",	Burst128, 16, 64, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
186474a4d8c2SCharles.Forsyth { SYM_1011_DID,   0xff, "SYM53C1010",	Burst128, 16, 64, Prefetch|LocalRAM|BigFifo|Wide|Ultra|Ultra2 },
186574a4d8c2SCharles.Forsyth };
186674a4d8c2SCharles.Forsyth 
186774a4d8c2SCharles.Forsyth 
186874a4d8c2SCharles.Forsyth static int
xfunc(Controller * c,enum na_external x,unsigned long * v)186974a4d8c2SCharles.Forsyth xfunc(Controller *c, enum na_external x, unsigned long *v)
187074a4d8c2SCharles.Forsyth {
1871*8a8c2d74SCharles.Forsyth 	switch (x) {
187274a4d8c2SCharles.Forsyth 	default:
187374a4d8c2SCharles.Forsyth 		print("xfunc: can't find external %d\n", x);
187474a4d8c2SCharles.Forsyth 		return 0;
1875*8a8c2d74SCharles.Forsyth 	case X_scsi_id_buf:
1876*8a8c2d74SCharles.Forsyth 		*v = offsetof(Dsa, scsi_id_buf[0]);
1877*8a8c2d74SCharles.Forsyth 		break;
1878*8a8c2d74SCharles.Forsyth 	case X_msg_out_buf:
1879*8a8c2d74SCharles.Forsyth 		*v = offsetof(Dsa, msg_out_buf);
1880*8a8c2d74SCharles.Forsyth 		break;
1881*8a8c2d74SCharles.Forsyth 	case X_cmd_buf:
1882*8a8c2d74SCharles.Forsyth 		*v = offsetof(Dsa, cmd_buf);
1883*8a8c2d74SCharles.Forsyth 		break;
1884*8a8c2d74SCharles.Forsyth 	case X_data_buf:
1885*8a8c2d74SCharles.Forsyth 		*v = offsetof(Dsa, data_buf);
1886*8a8c2d74SCharles.Forsyth 		break;
1887*8a8c2d74SCharles.Forsyth 	case X_status_buf:
1888*8a8c2d74SCharles.Forsyth 		*v = offsetof(Dsa, status_buf);
1889*8a8c2d74SCharles.Forsyth 		break;
1890*8a8c2d74SCharles.Forsyth 	case X_dsa_head:
1891*8a8c2d74SCharles.Forsyth 		*v = DMASEG(&c->dsalist.head[0]);
1892*8a8c2d74SCharles.Forsyth 		break;
189374a4d8c2SCharles.Forsyth 	}
189474a4d8c2SCharles.Forsyth 	return 1;
189574a4d8c2SCharles.Forsyth }
189674a4d8c2SCharles.Forsyth 
189774a4d8c2SCharles.Forsyth static int
na_fixup(Controller * c,ulong pa_reg,struct na_patch * patch,int patches,int (* externval)(Controller *,int,ulong *))189874a4d8c2SCharles.Forsyth na_fixup(Controller *c, ulong pa_reg,
189974a4d8c2SCharles.Forsyth     struct na_patch *patch, int patches,
190074a4d8c2SCharles.Forsyth     int (*externval)(Controller*, int, ulong*))
190174a4d8c2SCharles.Forsyth {
190274a4d8c2SCharles.Forsyth 	int p;
190374a4d8c2SCharles.Forsyth 	int v;
190474a4d8c2SCharles.Forsyth 	ulong *script, pa_script;
190574a4d8c2SCharles.Forsyth 	unsigned long lw, lv;
190674a4d8c2SCharles.Forsyth 
190774a4d8c2SCharles.Forsyth 	script = c->script;
190874a4d8c2SCharles.Forsyth 	pa_script = c->scriptpa;
190974a4d8c2SCharles.Forsyth 	for (p = 0; p < patches; p++) {
191074a4d8c2SCharles.Forsyth 		switch (patch[p].type) {
191174a4d8c2SCharles.Forsyth 		case 1:
191274a4d8c2SCharles.Forsyth 			/* script relative */
191374a4d8c2SCharles.Forsyth 			script[patch[p].lwoff] += pa_script;
191474a4d8c2SCharles.Forsyth 			break;
191574a4d8c2SCharles.Forsyth 		case 2:
191674a4d8c2SCharles.Forsyth 			/* register i/o relative */
191774a4d8c2SCharles.Forsyth 			script[patch[p].lwoff] += pa_reg;
191874a4d8c2SCharles.Forsyth 			break;
191974a4d8c2SCharles.Forsyth 		case 3:
192074a4d8c2SCharles.Forsyth 			/* data external */
192174a4d8c2SCharles.Forsyth 			lw = script[patch[p].lwoff];
192274a4d8c2SCharles.Forsyth 			v = (lw >> 8) & 0xff;
192374a4d8c2SCharles.Forsyth 			if (!(*externval)(c, v, &lv))
192474a4d8c2SCharles.Forsyth 				return 0;
192574a4d8c2SCharles.Forsyth 			v = lv & 0xff;
192674a4d8c2SCharles.Forsyth 			script[patch[p].lwoff] = (lw & 0xffff00ffL) | (v << 8);
192774a4d8c2SCharles.Forsyth 			break;
192874a4d8c2SCharles.Forsyth 		case 4:
192974a4d8c2SCharles.Forsyth 			/* 32 bit external */
193074a4d8c2SCharles.Forsyth 			lw = script[patch[p].lwoff];
193174a4d8c2SCharles.Forsyth 			if (!(*externval)(c, lw, &lv))
193274a4d8c2SCharles.Forsyth 				return 0;
193374a4d8c2SCharles.Forsyth 			script[patch[p].lwoff] = lv;
193474a4d8c2SCharles.Forsyth 			break;
193574a4d8c2SCharles.Forsyth 		case 5:
193674a4d8c2SCharles.Forsyth 			/* 24 bit external */
193774a4d8c2SCharles.Forsyth 			lw = script[patch[p].lwoff];
193874a4d8c2SCharles.Forsyth 			if (!(*externval)(c, lw & 0xffffff, &lv))
193974a4d8c2SCharles.Forsyth 				return 0;
194074a4d8c2SCharles.Forsyth 			script[patch[p].lwoff] = (lw & 0xff000000L) | (lv & 0xffffffL);
194174a4d8c2SCharles.Forsyth 			break;
194274a4d8c2SCharles.Forsyth 		}
194374a4d8c2SCharles.Forsyth 	}
194474a4d8c2SCharles.Forsyth 	return 1;
194574a4d8c2SCharles.Forsyth }
194674a4d8c2SCharles.Forsyth 
194774a4d8c2SCharles.Forsyth static SDev*
sympnp(void)194874a4d8c2SCharles.Forsyth sympnp(void)
194974a4d8c2SCharles.Forsyth {
195074a4d8c2SCharles.Forsyth 	int ba;
195174a4d8c2SCharles.Forsyth 	Pcidev *p;
195274a4d8c2SCharles.Forsyth 	Variant *v;
195374a4d8c2SCharles.Forsyth 	void *scriptma;
195474a4d8c2SCharles.Forsyth 	Controller *ctlr;
195574a4d8c2SCharles.Forsyth 	SDev *sdev, *head, *tail;
195674a4d8c2SCharles.Forsyth 	ulong regpa, *script, scriptpa;
195774a4d8c2SCharles.Forsyth 
195874a4d8c2SCharles.Forsyth 	p = nil;
195974a4d8c2SCharles.Forsyth 	head = tail = nil;
196074a4d8c2SCharles.Forsyth 	while(p = pcimatch(p, NCR_VID, 0)){
196174a4d8c2SCharles.Forsyth 		for(v = variant; v < &variant[nelem(variant)]; v++){
196274a4d8c2SCharles.Forsyth 			if(p->did == v->did && p->rid <= v->maxrid)
196374a4d8c2SCharles.Forsyth 				break;
196474a4d8c2SCharles.Forsyth 		}
196574a4d8c2SCharles.Forsyth 		if(v >= &variant[nelem(variant)])
196674a4d8c2SCharles.Forsyth 			continue;
1967*8a8c2d74SCharles.Forsyth 		print("sd53c8xx: %s rev. 0x%2.2x intr=%d command=%4.4uX\n",
196874a4d8c2SCharles.Forsyth 			v->name, p->rid, p->intl, p->pcr);
196974a4d8c2SCharles.Forsyth 
197074a4d8c2SCharles.Forsyth 		regpa = p->mem[1].bar;
197174a4d8c2SCharles.Forsyth 		ba = 2;
197274a4d8c2SCharles.Forsyth 		if(regpa & 0x04){
197374a4d8c2SCharles.Forsyth 			if(p->mem[2].bar)
197474a4d8c2SCharles.Forsyth 				continue;
197574a4d8c2SCharles.Forsyth 			ba++;
197674a4d8c2SCharles.Forsyth 		}
197774a4d8c2SCharles.Forsyth 		regpa = upamalloc(regpa & ~0x0F, p->mem[1].size, 0);
197874a4d8c2SCharles.Forsyth 		if(regpa == 0)
197974a4d8c2SCharles.Forsyth 			continue;
198074a4d8c2SCharles.Forsyth 
198174a4d8c2SCharles.Forsyth 		script = nil;
198274a4d8c2SCharles.Forsyth 		scriptpa = 0;
198374a4d8c2SCharles.Forsyth 		scriptma = nil;
198474a4d8c2SCharles.Forsyth 		if((v->feature & LocalRAM) && sizeof(na_script) <= 4096){
198574a4d8c2SCharles.Forsyth 			scriptpa = p->mem[ba].bar;
198674a4d8c2SCharles.Forsyth 			if((scriptpa & 0x04) && p->mem[ba+1].bar){
198774a4d8c2SCharles.Forsyth 				upafree(regpa, p->mem[1].size);
198874a4d8c2SCharles.Forsyth 				continue;
198974a4d8c2SCharles.Forsyth 			}
199074a4d8c2SCharles.Forsyth 			scriptpa = upamalloc(scriptpa & ~0x0F,
199174a4d8c2SCharles.Forsyth 					p->mem[ba].size, 0);
199274a4d8c2SCharles.Forsyth 			if(scriptpa)
199374a4d8c2SCharles.Forsyth 				script = KADDR(scriptpa);
199474a4d8c2SCharles.Forsyth 		}
199574a4d8c2SCharles.Forsyth 		if(scriptpa == 0){
199674a4d8c2SCharles.Forsyth 			/*
199774a4d8c2SCharles.Forsyth 			 * Either the map failed, or this chip does not have
199874a4d8c2SCharles.Forsyth 			 * local RAM. It will need a copy of the microcode.
199974a4d8c2SCharles.Forsyth 			 */
200074a4d8c2SCharles.Forsyth 			scriptma = malloc(sizeof(na_script));
200174a4d8c2SCharles.Forsyth 			if(scriptma == nil){
200274a4d8c2SCharles.Forsyth 				upafree(regpa, p->mem[1].size);
200374a4d8c2SCharles.Forsyth 				continue;
200474a4d8c2SCharles.Forsyth 			}
200574a4d8c2SCharles.Forsyth 			scriptpa = DMASEG(scriptma);
200674a4d8c2SCharles.Forsyth 			script = scriptma;
200774a4d8c2SCharles.Forsyth 		}
200874a4d8c2SCharles.Forsyth 
200974a4d8c2SCharles.Forsyth 		ctlr = malloc(sizeof(Controller));
201074a4d8c2SCharles.Forsyth 		sdev = malloc(sizeof(SDev));
201174a4d8c2SCharles.Forsyth 		if(ctlr == nil || sdev == nil){
201274a4d8c2SCharles.Forsyth buggery:
201374a4d8c2SCharles.Forsyth 			if(ctlr)
201474a4d8c2SCharles.Forsyth 				free(ctlr);
201574a4d8c2SCharles.Forsyth 			if(sdev)
201674a4d8c2SCharles.Forsyth 				free(sdev);
201774a4d8c2SCharles.Forsyth 			if(scriptma)
201874a4d8c2SCharles.Forsyth 				free(scriptma);
201974a4d8c2SCharles.Forsyth 			else
202074a4d8c2SCharles.Forsyth 				upafree(scriptpa, p->mem[ba].size);
202174a4d8c2SCharles.Forsyth 			upafree(regpa, p->mem[1].size);
202274a4d8c2SCharles.Forsyth 			continue;
202374a4d8c2SCharles.Forsyth 		}
202474a4d8c2SCharles.Forsyth 
202574a4d8c2SCharles.Forsyth 		ctlr->n = KADDR(regpa);
202674a4d8c2SCharles.Forsyth 		ctlr->v = v;
202774a4d8c2SCharles.Forsyth 		ctlr->script = script;
202874a4d8c2SCharles.Forsyth 		memmove(ctlr->script, na_script, sizeof(na_script));
202974a4d8c2SCharles.Forsyth 		ctlr->scriptpa = scriptpa;
203074a4d8c2SCharles.Forsyth 		if(!na_fixup(ctlr, regpa, na_patches, NA_PATCHES, xfunc)){
203174a4d8c2SCharles.Forsyth 			print("script fixup failed\n");
203274a4d8c2SCharles.Forsyth 			goto buggery;
203374a4d8c2SCharles.Forsyth 		}
203474a4d8c2SCharles.Forsyth 		swabl(ctlr->script, ctlr->script, sizeof(na_script));
203574a4d8c2SCharles.Forsyth 
203674a4d8c2SCharles.Forsyth 		ctlr->dsalist.freechain = 0;
203774a4d8c2SCharles.Forsyth 		lesetl(ctlr->dsalist.head, 0);
203874a4d8c2SCharles.Forsyth 
203974a4d8c2SCharles.Forsyth 		ctlr->pcidev = p;
204074a4d8c2SCharles.Forsyth 
204174a4d8c2SCharles.Forsyth 		sdev->ifc = &sd53c8xxifc;
204274a4d8c2SCharles.Forsyth 		sdev->ctlr = ctlr;
204374a4d8c2SCharles.Forsyth 		if(!(v->feature & Wide))
204474a4d8c2SCharles.Forsyth 			sdev->nunit = 8;
204574a4d8c2SCharles.Forsyth 		else
204674a4d8c2SCharles.Forsyth 			sdev->nunit = MAXTARGET;
204774a4d8c2SCharles.Forsyth 		ctlr->sdev = sdev;
204874a4d8c2SCharles.Forsyth 
204974a4d8c2SCharles.Forsyth 		if(head != nil)
205074a4d8c2SCharles.Forsyth 			tail->next = sdev;
205174a4d8c2SCharles.Forsyth 		else
205274a4d8c2SCharles.Forsyth 			head = sdev;
205374a4d8c2SCharles.Forsyth 		tail = sdev;
205474a4d8c2SCharles.Forsyth 	}
205574a4d8c2SCharles.Forsyth 
205674a4d8c2SCharles.Forsyth 	return head;
205774a4d8c2SCharles.Forsyth }
205874a4d8c2SCharles.Forsyth 
205974a4d8c2SCharles.Forsyth static SDev*
symid(SDev * sdev)206074a4d8c2SCharles.Forsyth symid(SDev* sdev)
206174a4d8c2SCharles.Forsyth {
206274a4d8c2SCharles.Forsyth 	return scsiid(sdev, &sd53c8xxifc);
206374a4d8c2SCharles.Forsyth }
206474a4d8c2SCharles.Forsyth 
206574a4d8c2SCharles.Forsyth static int
symenable(SDev * sdev)206674a4d8c2SCharles.Forsyth symenable(SDev* sdev)
206774a4d8c2SCharles.Forsyth {
206874a4d8c2SCharles.Forsyth 	Pcidev *pcidev;
206974a4d8c2SCharles.Forsyth 	Controller *ctlr;
207074a4d8c2SCharles.Forsyth 	//char name[NAMELEN];
207174a4d8c2SCharles.Forsyth 
207274a4d8c2SCharles.Forsyth 	ctlr = sdev->ctlr;
207374a4d8c2SCharles.Forsyth 	pcidev = ctlr->pcidev;
207474a4d8c2SCharles.Forsyth 
207574a4d8c2SCharles.Forsyth 	pcisetbme(pcidev);
207674a4d8c2SCharles.Forsyth 	//snprint(name, NAMELEN, "%s (%s)", sdev->name, sdev->ifc->name);
207774a4d8c2SCharles.Forsyth 	intrenable(pcidev->intl, interrupt, ctlr, pcidev->tbdf, name);
207874a4d8c2SCharles.Forsyth 
207974a4d8c2SCharles.Forsyth 	ilock(ctlr);
208074a4d8c2SCharles.Forsyth 	synctabinit(ctlr);
208174a4d8c2SCharles.Forsyth 	cribbios(ctlr);
208274a4d8c2SCharles.Forsyth 	reset(ctlr);
208374a4d8c2SCharles.Forsyth 	iunlock(ctlr);
208474a4d8c2SCharles.Forsyth 
208574a4d8c2SCharles.Forsyth 	return 1;
208674a4d8c2SCharles.Forsyth }
208774a4d8c2SCharles.Forsyth 
208874a4d8c2SCharles.Forsyth static int
symdisable(SDev * sdev)208974a4d8c2SCharles.Forsyth symdisable(SDev* sdev)
209074a4d8c2SCharles.Forsyth {
209174a4d8c2SCharles.Forsyth 	Ncr *n;
209274a4d8c2SCharles.Forsyth 	Controller *ctlr;
209374a4d8c2SCharles.Forsyth 
209474a4d8c2SCharles.Forsyth 	ctlr = sdev->ctlr;
209574a4d8c2SCharles.Forsyth 	n = ctlr->n;
209674a4d8c2SCharles.Forsyth 
209774a4d8c2SCharles.Forsyth 	n->istat = Srst;		/* software reset */
209874a4d8c2SCharles.Forsyth 	microdelay(1);
209974a4d8c2SCharles.Forsyth 	n->istat = 0;
210074a4d8c2SCharles.Forsyth 
210174a4d8c2SCharles.Forsyth 	n->scntl1 |= (1 << 3);		/* bus reset */
210274a4d8c2SCharles.Forsyth 	delay(500);
210374a4d8c2SCharles.Forsyth 	n->scntl1 &= ~(1 << 3);
210474a4d8c2SCharles.Forsyth 
210574a4d8c2SCharles.Forsyth 	return 1;
210674a4d8c2SCharles.Forsyth }
210774a4d8c2SCharles.Forsyth 
210874a4d8c2SCharles.Forsyth SDifc sd53c8xxifc = {
210974a4d8c2SCharles.Forsyth 	"53c8xx",			/* name */
211074a4d8c2SCharles.Forsyth 
211174a4d8c2SCharles.Forsyth 	sympnp,				/* pnp */
211274a4d8c2SCharles.Forsyth 	nil,				/* legacy */
211374a4d8c2SCharles.Forsyth 	symid,				/* id */
211474a4d8c2SCharles.Forsyth 	symenable,			/* enable */
211574a4d8c2SCharles.Forsyth 	symdisable,			/* disable */
211674a4d8c2SCharles.Forsyth 
211774a4d8c2SCharles.Forsyth 	scsiverify,			/* verify */
211874a4d8c2SCharles.Forsyth 	scsionline,			/* online */
211974a4d8c2SCharles.Forsyth 	symrio,				/* rio */
212074a4d8c2SCharles.Forsyth 	nil,				/* rctl */
212174a4d8c2SCharles.Forsyth 	nil,				/* wctl */
212274a4d8c2SCharles.Forsyth 
212374a4d8c2SCharles.Forsyth 	scsibio,			/* bio */
212474a4d8c2SCharles.Forsyth };
2125