xref: /OK3568_Linux_fs/kernel/drivers/scsi/wd33c93.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 1996 John Shifflett, GeoLog Consulting
4*4882a593Smuzhiyun  *    john@geolog.com
5*4882a593Smuzhiyun  *    jshiffle@netcom.com
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun /*
9*4882a593Smuzhiyun  * Drew Eckhardt's excellent 'Generic NCR5380' sources from Linux-PC
10*4882a593Smuzhiyun  * provided much of the inspiration and some of the code for this
11*4882a593Smuzhiyun  * driver. Everything I know about Amiga DMA was gleaned from careful
12*4882a593Smuzhiyun  * reading of Hamish Mcdonald's original wd33c93 driver; in fact, I
13*4882a593Smuzhiyun  * borrowed shamelessly from all over that source. Thanks Hamish!
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * _This_ driver is (I feel) an improvement over the old one in
16*4882a593Smuzhiyun  * several respects:
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  *    -  Target Disconnection/Reconnection  is now supported. Any
19*4882a593Smuzhiyun  *          system with more than one device active on the SCSI bus
20*4882a593Smuzhiyun  *          will benefit from this. The driver defaults to what I
21*4882a593Smuzhiyun  *          call 'adaptive disconnect' - meaning that each command
22*4882a593Smuzhiyun  *          is evaluated individually as to whether or not it should
23*4882a593Smuzhiyun  *          be run with the option to disconnect/reselect (if the
24*4882a593Smuzhiyun  *          device chooses), or as a "SCSI-bus-hog".
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  *    -  Synchronous data transfers are now supported. Because of
27*4882a593Smuzhiyun  *          a few devices that choke after telling the driver that
28*4882a593Smuzhiyun  *          they can do sync transfers, we don't automatically use
29*4882a593Smuzhiyun  *          this faster protocol - it can be enabled via the command-
30*4882a593Smuzhiyun  *          line on a device-by-device basis.
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  *    -  Runtime operating parameters can now be specified through
33*4882a593Smuzhiyun  *       the 'amiboot' or the 'insmod' command line. For amiboot do:
34*4882a593Smuzhiyun  *          "amiboot [usual stuff] wd33c93=blah,blah,blah"
35*4882a593Smuzhiyun  *       The defaults should be good for most people. See the comment
36*4882a593Smuzhiyun  *       for 'setup_strings' below for more details.
37*4882a593Smuzhiyun  *
38*4882a593Smuzhiyun  *    -  The old driver relied exclusively on what the Western Digital
39*4882a593Smuzhiyun  *          docs call "Combination Level 2 Commands", which are a great
40*4882a593Smuzhiyun  *          idea in that the CPU is relieved of a lot of interrupt
41*4882a593Smuzhiyun  *          overhead. However, by accepting a certain (user-settable)
42*4882a593Smuzhiyun  *          amount of additional interrupts, this driver achieves
43*4882a593Smuzhiyun  *          better control over the SCSI bus, and data transfers are
44*4882a593Smuzhiyun  *          almost as fast while being much easier to define, track,
45*4882a593Smuzhiyun  *          and debug.
46*4882a593Smuzhiyun  *
47*4882a593Smuzhiyun  *
48*4882a593Smuzhiyun  * TODO:
49*4882a593Smuzhiyun  *       more speed. linked commands.
50*4882a593Smuzhiyun  *
51*4882a593Smuzhiyun  *
52*4882a593Smuzhiyun  * People with bug reports, wish-lists, complaints, comments,
53*4882a593Smuzhiyun  * or improvements are asked to pah-leeez email me (John Shifflett)
54*4882a593Smuzhiyun  * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get
55*4882a593Smuzhiyun  * this thing into as good a shape as possible, and I'm positive
56*4882a593Smuzhiyun  * there are lots of lurking bugs and "Stupid Places".
57*4882a593Smuzhiyun  *
58*4882a593Smuzhiyun  * Updates:
59*4882a593Smuzhiyun  *
60*4882a593Smuzhiyun  * Added support for pre -A chips, which don't have advanced features
61*4882a593Smuzhiyun  * and will generate CSR_RESEL rather than CSR_RESEL_AM.
62*4882a593Smuzhiyun  *	Richard Hirst <richard@sleepie.demon.co.uk>  August 2000
63*4882a593Smuzhiyun  *
64*4882a593Smuzhiyun  * Added support for Burst Mode DMA and Fast SCSI. Enabled the use of
65*4882a593Smuzhiyun  * default_sx_per for asynchronous data transfers. Added adjustment
66*4882a593Smuzhiyun  * of transfer periods in sx_table to the actual input-clock.
67*4882a593Smuzhiyun  *  peter fuerst <post@pfrst.de>  February 2007
68*4882a593Smuzhiyun  */
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #include <linux/module.h>
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #include <linux/string.h>
73*4882a593Smuzhiyun #include <linux/delay.h>
74*4882a593Smuzhiyun #include <linux/init.h>
75*4882a593Smuzhiyun #include <linux/interrupt.h>
76*4882a593Smuzhiyun #include <linux/blkdev.h>
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun #include <scsi/scsi.h>
79*4882a593Smuzhiyun #include <scsi/scsi_cmnd.h>
80*4882a593Smuzhiyun #include <scsi/scsi_device.h>
81*4882a593Smuzhiyun #include <scsi/scsi_host.h>
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #include <asm/irq.h>
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #include "wd33c93.h"
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #define optimum_sx_per(hostdata) (hostdata)->sx_table[1].period_ns
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun #define WD33C93_VERSION    "1.26++"
91*4882a593Smuzhiyun #define WD33C93_DATE       "10/Feb/2007"
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun MODULE_AUTHOR("John Shifflett");
94*4882a593Smuzhiyun MODULE_DESCRIPTION("Generic WD33C93 SCSI driver");
95*4882a593Smuzhiyun MODULE_LICENSE("GPL");
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun /*
98*4882a593Smuzhiyun  * 'setup_strings' is a single string used to pass operating parameters and
99*4882a593Smuzhiyun  * settings from the kernel/module command-line to the driver. 'setup_args[]'
100*4882a593Smuzhiyun  * is an array of strings that define the compile-time default values for
101*4882a593Smuzhiyun  * these settings. If Linux boots with an amiboot or insmod command-line,
102*4882a593Smuzhiyun  * those settings are combined with 'setup_args[]'. Note that amiboot
103*4882a593Smuzhiyun  * command-lines are prefixed with "wd33c93=" while insmod uses a
104*4882a593Smuzhiyun  * "setup_strings=" prefix. The driver recognizes the following keywords
105*4882a593Smuzhiyun  * (lower case required) and arguments:
106*4882a593Smuzhiyun  *
107*4882a593Smuzhiyun  * -  nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with
108*4882a593Smuzhiyun  *                    the 7 possible SCSI devices. Set a bit to negotiate for
109*4882a593Smuzhiyun  *                    asynchronous transfers on that device. To maintain
110*4882a593Smuzhiyun  *                    backwards compatibility, a command-line such as
111*4882a593Smuzhiyun  *                    "wd33c93=255" will be automatically translated to
112*4882a593Smuzhiyun  *                    "wd33c93=nosync:0xff".
113*4882a593Smuzhiyun  * -  nodma:x        -x = 1 to disable DMA, x = 0 to enable it. Argument is
114*4882a593Smuzhiyun  *                    optional - if not present, same as "nodma:1".
115*4882a593Smuzhiyun  * -  period:ns      -ns is the minimum # of nanoseconds in a SCSI data transfer
116*4882a593Smuzhiyun  *                    period. Default is 500; acceptable values are 250 - 1000.
117*4882a593Smuzhiyun  * -  disconnect:x   -x = 0 to never allow disconnects, 2 to always allow them.
118*4882a593Smuzhiyun  *                    x = 1 does 'adaptive' disconnects, which is the default
119*4882a593Smuzhiyun  *                    and generally the best choice.
120*4882a593Smuzhiyun  * -  debug:x        -If 'DEBUGGING_ON' is defined, x is a bit mask that causes
121*4882a593Smuzhiyun  *                    various types of debug output to printed - see the DB_xxx
122*4882a593Smuzhiyun  *                    defines in wd33c93.h
123*4882a593Smuzhiyun  * -  clock:x        -x = clock input in MHz for WD33c93 chip. Normal values
124*4882a593Smuzhiyun  *                    would be from 8 through 20. Default is 8.
125*4882a593Smuzhiyun  * -  burst:x        -x = 1 to use Burst Mode (or Demand-Mode) DMA, x = 0 to use
126*4882a593Smuzhiyun  *                    Single Byte DMA, which is the default. Argument is
127*4882a593Smuzhiyun  *                    optional - if not present, same as "burst:1".
128*4882a593Smuzhiyun  * -  fast:x         -x = 1 to enable Fast SCSI, which is only effective with
129*4882a593Smuzhiyun  *                    input-clock divisor 4 (WD33C93_FS_16_20), x = 0 to disable
130*4882a593Smuzhiyun  *                    it, which is the default.  Argument is optional - if not
131*4882a593Smuzhiyun  *                    present, same as "fast:1".
132*4882a593Smuzhiyun  * -  next           -No argument. Used to separate blocks of keywords when
133*4882a593Smuzhiyun  *                    there's more than one host adapter in the system.
134*4882a593Smuzhiyun  *
135*4882a593Smuzhiyun  * Syntax Notes:
136*4882a593Smuzhiyun  * -  Numeric arguments can be decimal or the '0x' form of hex notation. There
137*4882a593Smuzhiyun  *    _must_ be a colon between a keyword and its numeric argument, with no
138*4882a593Smuzhiyun  *    spaces.
139*4882a593Smuzhiyun  * -  Keywords are separated by commas, no spaces, in the standard kernel
140*4882a593Smuzhiyun  *    command-line manner.
141*4882a593Smuzhiyun  * -  A keyword in the 'nth' comma-separated command-line member will overwrite
142*4882a593Smuzhiyun  *    the 'nth' element of setup_args[]. A blank command-line member (in
143*4882a593Smuzhiyun  *    other words, a comma with no preceding keyword) will _not_ overwrite
144*4882a593Smuzhiyun  *    the corresponding setup_args[] element.
145*4882a593Smuzhiyun  * -  If a keyword is used more than once, the first one applies to the first
146*4882a593Smuzhiyun  *    SCSI host found, the second to the second card, etc, unless the 'next'
147*4882a593Smuzhiyun  *    keyword is used to change the order.
148*4882a593Smuzhiyun  *
149*4882a593Smuzhiyun  * Some amiboot examples (for insmod, use 'setup_strings' instead of 'wd33c93'):
150*4882a593Smuzhiyun  * -  wd33c93=nosync:255
151*4882a593Smuzhiyun  * -  wd33c93=nodma
152*4882a593Smuzhiyun  * -  wd33c93=nodma:1
153*4882a593Smuzhiyun  * -  wd33c93=disconnect:2,nosync:0x08,period:250
154*4882a593Smuzhiyun  * -  wd33c93=debug:0x1c
155*4882a593Smuzhiyun  */
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun /* Normally, no defaults are specified */
158*4882a593Smuzhiyun static char *setup_args[] = { "", "", "", "", "", "", "", "", "", "" };
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun static char *setup_strings;
161*4882a593Smuzhiyun module_param(setup_strings, charp, 0);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun static void wd33c93_execute(struct Scsi_Host *instance);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun #ifdef CONFIG_WD33C93_PIO
166*4882a593Smuzhiyun static inline uchar
read_wd33c93(const wd33c93_regs regs,uchar reg_num)167*4882a593Smuzhiyun read_wd33c93(const wd33c93_regs regs, uchar reg_num)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	uchar data;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	outb(reg_num, regs.SASR);
172*4882a593Smuzhiyun 	data = inb(regs.SCMD);
173*4882a593Smuzhiyun 	return data;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun static inline unsigned long
read_wd33c93_count(const wd33c93_regs regs)177*4882a593Smuzhiyun read_wd33c93_count(const wd33c93_regs regs)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	unsigned long value;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	outb(WD_TRANSFER_COUNT_MSB, regs.SASR);
182*4882a593Smuzhiyun 	value = inb(regs.SCMD) << 16;
183*4882a593Smuzhiyun 	value |= inb(regs.SCMD) << 8;
184*4882a593Smuzhiyun 	value |= inb(regs.SCMD);
185*4882a593Smuzhiyun 	return value;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun static inline uchar
read_aux_stat(const wd33c93_regs regs)189*4882a593Smuzhiyun read_aux_stat(const wd33c93_regs regs)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	return inb(regs.SASR);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun static inline void
write_wd33c93(const wd33c93_regs regs,uchar reg_num,uchar value)195*4882a593Smuzhiyun write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun       outb(reg_num, regs.SASR);
198*4882a593Smuzhiyun       outb(value, regs.SCMD);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun static inline void
write_wd33c93_count(const wd33c93_regs regs,unsigned long value)202*4882a593Smuzhiyun write_wd33c93_count(const wd33c93_regs regs, unsigned long value)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	outb(WD_TRANSFER_COUNT_MSB, regs.SASR);
205*4882a593Smuzhiyun 	outb((value >> 16) & 0xff, regs.SCMD);
206*4882a593Smuzhiyun 	outb((value >> 8) & 0xff, regs.SCMD);
207*4882a593Smuzhiyun 	outb( value & 0xff, regs.SCMD);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun #define write_wd33c93_cmd(regs, cmd) \
211*4882a593Smuzhiyun 	write_wd33c93((regs), WD_COMMAND, (cmd))
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun static inline void
write_wd33c93_cdb(const wd33c93_regs regs,uint len,uchar cmnd[])214*4882a593Smuzhiyun write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[])
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	int i;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	outb(WD_CDB_1, regs.SASR);
219*4882a593Smuzhiyun 	for (i=0; i<len; i++)
220*4882a593Smuzhiyun 		outb(cmnd[i], regs.SCMD);
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun #else /* CONFIG_WD33C93_PIO */
224*4882a593Smuzhiyun static inline uchar
read_wd33c93(const wd33c93_regs regs,uchar reg_num)225*4882a593Smuzhiyun read_wd33c93(const wd33c93_regs regs, uchar reg_num)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	*regs.SASR = reg_num;
228*4882a593Smuzhiyun 	mb();
229*4882a593Smuzhiyun 	return (*regs.SCMD);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun static unsigned long
read_wd33c93_count(const wd33c93_regs regs)233*4882a593Smuzhiyun read_wd33c93_count(const wd33c93_regs regs)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	unsigned long value;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	*regs.SASR = WD_TRANSFER_COUNT_MSB;
238*4882a593Smuzhiyun 	mb();
239*4882a593Smuzhiyun 	value = *regs.SCMD << 16;
240*4882a593Smuzhiyun 	value |= *regs.SCMD << 8;
241*4882a593Smuzhiyun 	value |= *regs.SCMD;
242*4882a593Smuzhiyun 	mb();
243*4882a593Smuzhiyun 	return value;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun static inline uchar
read_aux_stat(const wd33c93_regs regs)247*4882a593Smuzhiyun read_aux_stat(const wd33c93_regs regs)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	return *regs.SASR;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun static inline void
write_wd33c93(const wd33c93_regs regs,uchar reg_num,uchar value)253*4882a593Smuzhiyun write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun 	*regs.SASR = reg_num;
256*4882a593Smuzhiyun 	mb();
257*4882a593Smuzhiyun 	*regs.SCMD = value;
258*4882a593Smuzhiyun 	mb();
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun static void
write_wd33c93_count(const wd33c93_regs regs,unsigned long value)262*4882a593Smuzhiyun write_wd33c93_count(const wd33c93_regs regs, unsigned long value)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	*regs.SASR = WD_TRANSFER_COUNT_MSB;
265*4882a593Smuzhiyun 	mb();
266*4882a593Smuzhiyun 	*regs.SCMD = value >> 16;
267*4882a593Smuzhiyun 	*regs.SCMD = value >> 8;
268*4882a593Smuzhiyun 	*regs.SCMD = value;
269*4882a593Smuzhiyun 	mb();
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun static inline void
write_wd33c93_cmd(const wd33c93_regs regs,uchar cmd)273*4882a593Smuzhiyun write_wd33c93_cmd(const wd33c93_regs regs, uchar cmd)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun 	*regs.SASR = WD_COMMAND;
276*4882a593Smuzhiyun 	mb();
277*4882a593Smuzhiyun 	*regs.SCMD = cmd;
278*4882a593Smuzhiyun 	mb();
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun static inline void
write_wd33c93_cdb(const wd33c93_regs regs,uint len,uchar cmnd[])282*4882a593Smuzhiyun write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[])
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	int i;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	*regs.SASR = WD_CDB_1;
287*4882a593Smuzhiyun 	for (i = 0; i < len; i++)
288*4882a593Smuzhiyun 		*regs.SCMD = cmnd[i];
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun #endif /* CONFIG_WD33C93_PIO */
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun static inline uchar
read_1_byte(const wd33c93_regs regs)293*4882a593Smuzhiyun read_1_byte(const wd33c93_regs regs)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	uchar asr;
296*4882a593Smuzhiyun 	uchar x = 0;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
299*4882a593Smuzhiyun 	write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO | 0x80);
300*4882a593Smuzhiyun 	do {
301*4882a593Smuzhiyun 		asr = read_aux_stat(regs);
302*4882a593Smuzhiyun 		if (asr & ASR_DBR)
303*4882a593Smuzhiyun 			x = read_wd33c93(regs, WD_DATA);
304*4882a593Smuzhiyun 	} while (!(asr & ASR_INT));
305*4882a593Smuzhiyun 	return x;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun static int
round_period(unsigned int period,const struct sx_period * sx_table)309*4882a593Smuzhiyun round_period(unsigned int period, const struct sx_period *sx_table)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	int x;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	for (x = 1; sx_table[x].period_ns; x++) {
314*4882a593Smuzhiyun 		if ((period <= sx_table[x - 0].period_ns) &&
315*4882a593Smuzhiyun 		    (period > sx_table[x - 1].period_ns)) {
316*4882a593Smuzhiyun 			return x;
317*4882a593Smuzhiyun 		}
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 	return 7;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun /*
323*4882a593Smuzhiyun  * Calculate Synchronous Transfer Register value from SDTR code.
324*4882a593Smuzhiyun  */
325*4882a593Smuzhiyun static uchar
calc_sync_xfer(unsigned int period,unsigned int offset,unsigned int fast,const struct sx_period * sx_table)326*4882a593Smuzhiyun calc_sync_xfer(unsigned int period, unsigned int offset, unsigned int fast,
327*4882a593Smuzhiyun                const struct sx_period *sx_table)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun 	/* When doing Fast SCSI synchronous data transfers, the corresponding
330*4882a593Smuzhiyun 	 * value in 'sx_table' is two times the actually used transfer period.
331*4882a593Smuzhiyun 	 */
332*4882a593Smuzhiyun 	uchar result;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	if (offset && fast) {
335*4882a593Smuzhiyun 		fast = STR_FSS;
336*4882a593Smuzhiyun 		period *= 2;
337*4882a593Smuzhiyun 	} else {
338*4882a593Smuzhiyun 		fast = 0;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 	period *= 4;		/* convert SDTR code to ns */
341*4882a593Smuzhiyun 	result = sx_table[round_period(period,sx_table)].reg_value;
342*4882a593Smuzhiyun 	result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF;
343*4882a593Smuzhiyun 	result |= fast;
344*4882a593Smuzhiyun 	return result;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun /*
348*4882a593Smuzhiyun  * Calculate SDTR code bytes [3],[4] from period and offset.
349*4882a593Smuzhiyun  */
350*4882a593Smuzhiyun static inline void
calc_sync_msg(unsigned int period,unsigned int offset,unsigned int fast,uchar msg[2])351*4882a593Smuzhiyun calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast,
352*4882a593Smuzhiyun                 uchar  msg[2])
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun 	/* 'period' is a "normal"-mode value, like the ones in 'sx_table'. The
355*4882a593Smuzhiyun 	 * actually used transfer period for Fast SCSI synchronous data
356*4882a593Smuzhiyun 	 * transfers is half that value.
357*4882a593Smuzhiyun 	 */
358*4882a593Smuzhiyun 	period /= 4;
359*4882a593Smuzhiyun 	if (offset && fast)
360*4882a593Smuzhiyun 		period /= 2;
361*4882a593Smuzhiyun 	msg[0] = period;
362*4882a593Smuzhiyun 	msg[1] = offset;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun static int
wd33c93_queuecommand_lck(struct scsi_cmnd * cmd,void (* done)(struct scsi_cmnd *))366*4882a593Smuzhiyun wd33c93_queuecommand_lck(struct scsi_cmnd *cmd,
367*4882a593Smuzhiyun 		void (*done)(struct scsi_cmnd *))
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun 	struct WD33C93_hostdata *hostdata;
370*4882a593Smuzhiyun 	struct scsi_cmnd *tmp;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	DB(DB_QUEUE_COMMAND,
375*4882a593Smuzhiyun 	   printk("Q-%d-%02x( ", cmd->device->id, cmd->cmnd[0]))
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun /* Set up a few fields in the scsi_cmnd structure for our own use:
378*4882a593Smuzhiyun  *  - host_scribble is the pointer to the next cmd in the input queue
379*4882a593Smuzhiyun  *  - scsi_done points to the routine we call when a cmd is finished
380*4882a593Smuzhiyun  *  - result is what you'd expect
381*4882a593Smuzhiyun  */
382*4882a593Smuzhiyun 	cmd->host_scribble = NULL;
383*4882a593Smuzhiyun 	cmd->scsi_done = done;
384*4882a593Smuzhiyun 	cmd->result = 0;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun /* We use the Scsi_Pointer structure that's included with each command
387*4882a593Smuzhiyun  * as a scratchpad (as it's intended to be used!). The handy thing about
388*4882a593Smuzhiyun  * the SCp.xxx fields is that they're always associated with a given
389*4882a593Smuzhiyun  * cmd, and are preserved across disconnect-reselect. This means we
390*4882a593Smuzhiyun  * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages
391*4882a593Smuzhiyun  * if we keep all the critical pointers and counters in SCp:
392*4882a593Smuzhiyun  *  - SCp.ptr is the pointer into the RAM buffer
393*4882a593Smuzhiyun  *  - SCp.this_residual is the size of that buffer
394*4882a593Smuzhiyun  *  - SCp.buffer points to the current scatter-gather buffer
395*4882a593Smuzhiyun  *  - SCp.buffers_residual tells us how many S.G. buffers there are
396*4882a593Smuzhiyun  *  - SCp.have_data_in is not used
397*4882a593Smuzhiyun  *  - SCp.sent_command is not used
398*4882a593Smuzhiyun  *  - SCp.phase records this command's SRCID_ER bit setting
399*4882a593Smuzhiyun  */
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (scsi_bufflen(cmd)) {
402*4882a593Smuzhiyun 		cmd->SCp.buffer = scsi_sglist(cmd);
403*4882a593Smuzhiyun 		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
404*4882a593Smuzhiyun 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
405*4882a593Smuzhiyun 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
406*4882a593Smuzhiyun 	} else {
407*4882a593Smuzhiyun 		cmd->SCp.buffer = NULL;
408*4882a593Smuzhiyun 		cmd->SCp.buffers_residual = 0;
409*4882a593Smuzhiyun 		cmd->SCp.ptr = NULL;
410*4882a593Smuzhiyun 		cmd->SCp.this_residual = 0;
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun /* WD docs state that at the conclusion of a "LEVEL2" command, the
414*4882a593Smuzhiyun  * status byte can be retrieved from the LUN register. Apparently,
415*4882a593Smuzhiyun  * this is the case only for *uninterrupted* LEVEL2 commands! If
416*4882a593Smuzhiyun  * there are any unexpected phases entered, even if they are 100%
417*4882a593Smuzhiyun  * legal (different devices may choose to do things differently),
418*4882a593Smuzhiyun  * the LEVEL2 command sequence is exited. This often occurs prior
419*4882a593Smuzhiyun  * to receiving the status byte, in which case the driver does a
420*4882a593Smuzhiyun  * status phase interrupt and gets the status byte on its own.
421*4882a593Smuzhiyun  * While such a command can then be "resumed" (ie restarted to
422*4882a593Smuzhiyun  * finish up as a LEVEL2 command), the LUN register will NOT be
423*4882a593Smuzhiyun  * a valid status byte at the command's conclusion, and we must
424*4882a593Smuzhiyun  * use the byte obtained during the earlier interrupt. Here, we
425*4882a593Smuzhiyun  * preset SCp.Status to an illegal value (0xff) so that when
426*4882a593Smuzhiyun  * this command finally completes, we can tell where the actual
427*4882a593Smuzhiyun  * status byte is stored.
428*4882a593Smuzhiyun  */
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	cmd->SCp.Status = ILLEGAL_STATUS_BYTE;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	/*
433*4882a593Smuzhiyun 	 * Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE
434*4882a593Smuzhiyun 	 * commands are added to the head of the queue so that the desired
435*4882a593Smuzhiyun 	 * sense data is not lost before REQUEST_SENSE executes.
436*4882a593Smuzhiyun 	 */
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	spin_lock_irq(&hostdata->lock);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
441*4882a593Smuzhiyun 		cmd->host_scribble = (uchar *) hostdata->input_Q;
442*4882a593Smuzhiyun 		hostdata->input_Q = cmd;
443*4882a593Smuzhiyun 	} else {		/* find the end of the queue */
444*4882a593Smuzhiyun 		for (tmp = (struct scsi_cmnd *) hostdata->input_Q;
445*4882a593Smuzhiyun 		     tmp->host_scribble;
446*4882a593Smuzhiyun 		     tmp = (struct scsi_cmnd *) tmp->host_scribble) ;
447*4882a593Smuzhiyun 		tmp->host_scribble = (uchar *) cmd;
448*4882a593Smuzhiyun 	}
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun /* We know that there's at least one command in 'input_Q' now.
451*4882a593Smuzhiyun  * Go see if any of them are runnable!
452*4882a593Smuzhiyun  */
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	wd33c93_execute(cmd->device->host);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	DB(DB_QUEUE_COMMAND, printk(")Q "))
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	spin_unlock_irq(&hostdata->lock);
459*4882a593Smuzhiyun 	return 0;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun 
DEF_SCSI_QCMD(wd33c93_queuecommand)462*4882a593Smuzhiyun DEF_SCSI_QCMD(wd33c93_queuecommand)
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun /*
465*4882a593Smuzhiyun  * This routine attempts to start a scsi command. If the host_card is
466*4882a593Smuzhiyun  * already connected, we give up immediately. Otherwise, look through
467*4882a593Smuzhiyun  * the input_Q, using the first command we find that's intended
468*4882a593Smuzhiyun  * for a currently non-busy target/lun.
469*4882a593Smuzhiyun  *
470*4882a593Smuzhiyun  * wd33c93_execute() is always called with interrupts disabled or from
471*4882a593Smuzhiyun  * the wd33c93_intr itself, which means that a wd33c93 interrupt
472*4882a593Smuzhiyun  * cannot occur while we are in here.
473*4882a593Smuzhiyun  */
474*4882a593Smuzhiyun static void
475*4882a593Smuzhiyun wd33c93_execute(struct Scsi_Host *instance)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	struct WD33C93_hostdata *hostdata =
478*4882a593Smuzhiyun 	    (struct WD33C93_hostdata *) instance->hostdata;
479*4882a593Smuzhiyun 	const wd33c93_regs regs = hostdata->regs;
480*4882a593Smuzhiyun 	struct scsi_cmnd *cmd, *prev;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	DB(DB_EXECUTE, printk("EX("))
483*4882a593Smuzhiyun 	if (hostdata->selecting || hostdata->connected) {
484*4882a593Smuzhiyun 		DB(DB_EXECUTE, printk(")EX-0 "))
485*4882a593Smuzhiyun 		return;
486*4882a593Smuzhiyun 	}
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	/*
489*4882a593Smuzhiyun 	 * Search through the input_Q for a command destined
490*4882a593Smuzhiyun 	 * for an idle target/lun.
491*4882a593Smuzhiyun 	 */
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	cmd = (struct scsi_cmnd *) hostdata->input_Q;
494*4882a593Smuzhiyun 	prev = NULL;
495*4882a593Smuzhiyun 	while (cmd) {
496*4882a593Smuzhiyun 		if (!(hostdata->busy[cmd->device->id] &
497*4882a593Smuzhiyun 		      (1 << (cmd->device->lun & 0xff))))
498*4882a593Smuzhiyun 			break;
499*4882a593Smuzhiyun 		prev = cmd;
500*4882a593Smuzhiyun 		cmd = (struct scsi_cmnd *) cmd->host_scribble;
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	/* quit if queue empty or all possible targets are busy */
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	if (!cmd) {
506*4882a593Smuzhiyun 		DB(DB_EXECUTE, printk(")EX-1 "))
507*4882a593Smuzhiyun 		return;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	/*  remove command from queue */
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	if (prev)
513*4882a593Smuzhiyun 		prev->host_scribble = cmd->host_scribble;
514*4882a593Smuzhiyun 	else
515*4882a593Smuzhiyun 		hostdata->input_Q = (struct scsi_cmnd *) cmd->host_scribble;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun #ifdef PROC_STATISTICS
518*4882a593Smuzhiyun 	hostdata->cmd_cnt[cmd->device->id]++;
519*4882a593Smuzhiyun #endif
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	/*
522*4882a593Smuzhiyun 	 * Start the selection process
523*4882a593Smuzhiyun 	 */
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	if (cmd->sc_data_direction == DMA_TO_DEVICE)
526*4882a593Smuzhiyun 		write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id);
527*4882a593Smuzhiyun 	else
528*4882a593Smuzhiyun 		write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun /* Now we need to figure out whether or not this command is a good
531*4882a593Smuzhiyun  * candidate for disconnect/reselect. We guess to the best of our
532*4882a593Smuzhiyun  * ability, based on a set of hierarchical rules. When several
533*4882a593Smuzhiyun  * devices are operating simultaneously, disconnects are usually
534*4882a593Smuzhiyun  * an advantage. In a single device system, or if only 1 device
535*4882a593Smuzhiyun  * is being accessed, transfers usually go faster if disconnects
536*4882a593Smuzhiyun  * are not allowed:
537*4882a593Smuzhiyun  *
538*4882a593Smuzhiyun  * + Commands should NEVER disconnect if hostdata->disconnect =
539*4882a593Smuzhiyun  *   DIS_NEVER (this holds for tape drives also), and ALWAYS
540*4882a593Smuzhiyun  *   disconnect if hostdata->disconnect = DIS_ALWAYS.
541*4882a593Smuzhiyun  * + Tape drive commands should always be allowed to disconnect.
542*4882a593Smuzhiyun  * + Disconnect should be allowed if disconnected_Q isn't empty.
543*4882a593Smuzhiyun  * + Commands should NOT disconnect if input_Q is empty.
544*4882a593Smuzhiyun  * + Disconnect should be allowed if there are commands in input_Q
545*4882a593Smuzhiyun  *   for a different target/lun. In this case, the other commands
546*4882a593Smuzhiyun  *   should be made disconnect-able, if not already.
547*4882a593Smuzhiyun  *
548*4882a593Smuzhiyun  * I know, I know - this code would flunk me out of any
549*4882a593Smuzhiyun  * "C Programming 101" class ever offered. But it's easy
550*4882a593Smuzhiyun  * to change around and experiment with for now.
551*4882a593Smuzhiyun  */
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	cmd->SCp.phase = 0;	/* assume no disconnect */
554*4882a593Smuzhiyun 	if (hostdata->disconnect == DIS_NEVER)
555*4882a593Smuzhiyun 		goto no;
556*4882a593Smuzhiyun 	if (hostdata->disconnect == DIS_ALWAYS)
557*4882a593Smuzhiyun 		goto yes;
558*4882a593Smuzhiyun 	if (cmd->device->type == 1)	/* tape drive? */
559*4882a593Smuzhiyun 		goto yes;
560*4882a593Smuzhiyun 	if (hostdata->disconnected_Q)	/* other commands disconnected? */
561*4882a593Smuzhiyun 		goto yes;
562*4882a593Smuzhiyun 	if (!(hostdata->input_Q))	/* input_Q empty? */
563*4882a593Smuzhiyun 		goto no;
564*4882a593Smuzhiyun 	for (prev = (struct scsi_cmnd *) hostdata->input_Q; prev;
565*4882a593Smuzhiyun 	     prev = (struct scsi_cmnd *) prev->host_scribble) {
566*4882a593Smuzhiyun 		if ((prev->device->id != cmd->device->id) ||
567*4882a593Smuzhiyun 		    (prev->device->lun != cmd->device->lun)) {
568*4882a593Smuzhiyun 			for (prev = (struct scsi_cmnd *) hostdata->input_Q; prev;
569*4882a593Smuzhiyun 			     prev = (struct scsi_cmnd *) prev->host_scribble)
570*4882a593Smuzhiyun 				prev->SCp.phase = 1;
571*4882a593Smuzhiyun 			goto yes;
572*4882a593Smuzhiyun 		}
573*4882a593Smuzhiyun 	}
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	goto no;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun  yes:
578*4882a593Smuzhiyun 	cmd->SCp.phase = 1;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun #ifdef PROC_STATISTICS
581*4882a593Smuzhiyun 	hostdata->disc_allowed_cnt[cmd->device->id]++;
582*4882a593Smuzhiyun #endif
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun  no:
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	write_wd33c93(regs, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0));
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	write_wd33c93(regs, WD_TARGET_LUN, (u8)cmd->device->lun);
589*4882a593Smuzhiyun 	write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
590*4882a593Smuzhiyun 		      hostdata->sync_xfer[cmd->device->id]);
591*4882a593Smuzhiyun 	hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF));
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	if ((hostdata->level2 == L2_NONE) ||
594*4882a593Smuzhiyun 	    (hostdata->sync_stat[cmd->device->id] == SS_UNSET)) {
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 		/*
597*4882a593Smuzhiyun 		 * Do a 'Select-With-ATN' command. This will end with
598*4882a593Smuzhiyun 		 * one of the following interrupts:
599*4882a593Smuzhiyun 		 *    CSR_RESEL_AM:  failure - can try again later.
600*4882a593Smuzhiyun 		 *    CSR_TIMEOUT:   failure - give up.
601*4882a593Smuzhiyun 		 *    CSR_SELECT:    success - proceed.
602*4882a593Smuzhiyun 		 */
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 		hostdata->selecting = cmd;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun /* Every target has its own synchronous transfer setting, kept in the
607*4882a593Smuzhiyun  * sync_xfer array, and a corresponding status byte in sync_stat[].
608*4882a593Smuzhiyun  * Each target's sync_stat[] entry is initialized to SX_UNSET, and its
609*4882a593Smuzhiyun  * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET
610*4882a593Smuzhiyun  * means that the parameters are undetermined as yet, and that we
611*4882a593Smuzhiyun  * need to send an SDTR message to this device after selection is
612*4882a593Smuzhiyun  * complete: We set SS_FIRST to tell the interrupt routine to do so.
613*4882a593Smuzhiyun  * If we've been asked not to try synchronous transfers on this
614*4882a593Smuzhiyun  * target (and _all_ luns within it), we'll still send the SDTR message
615*4882a593Smuzhiyun  * later, but at that time we'll negotiate for async by specifying a
616*4882a593Smuzhiyun  * sync fifo depth of 0.
617*4882a593Smuzhiyun  */
618*4882a593Smuzhiyun 		if (hostdata->sync_stat[cmd->device->id] == SS_UNSET)
619*4882a593Smuzhiyun 			hostdata->sync_stat[cmd->device->id] = SS_FIRST;
620*4882a593Smuzhiyun 		hostdata->state = S_SELECTING;
621*4882a593Smuzhiyun 		write_wd33c93_count(regs, 0);	/* guarantee a DATA_PHASE interrupt */
622*4882a593Smuzhiyun 		write_wd33c93_cmd(regs, WD_CMD_SEL_ATN);
623*4882a593Smuzhiyun 	} else {
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 		/*
626*4882a593Smuzhiyun 		 * Do a 'Select-With-ATN-Xfer' command. This will end with
627*4882a593Smuzhiyun 		 * one of the following interrupts:
628*4882a593Smuzhiyun 		 *    CSR_RESEL_AM:  failure - can try again later.
629*4882a593Smuzhiyun 		 *    CSR_TIMEOUT:   failure - give up.
630*4882a593Smuzhiyun 		 *    anything else: success - proceed.
631*4882a593Smuzhiyun 		 */
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 		hostdata->connected = cmd;
634*4882a593Smuzhiyun 		write_wd33c93(regs, WD_COMMAND_PHASE, 0);
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 		/* copy command_descriptor_block into WD chip
637*4882a593Smuzhiyun 		 * (take advantage of auto-incrementing)
638*4882a593Smuzhiyun 		 */
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 		write_wd33c93_cdb(regs, cmd->cmd_len, cmd->cmnd);
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 		/* The wd33c93 only knows about Group 0, 1, and 5 commands when
643*4882a593Smuzhiyun 		 * it's doing a 'select-and-transfer'. To be safe, we write the
644*4882a593Smuzhiyun 		 * size of the CDB into the OWN_ID register for every case. This
645*4882a593Smuzhiyun 		 * way there won't be problems with vendor-unique, audio, etc.
646*4882a593Smuzhiyun 		 */
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 		write_wd33c93(regs, WD_OWN_ID, cmd->cmd_len);
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 		/* When doing a non-disconnect command with DMA, we can save
651*4882a593Smuzhiyun 		 * ourselves a DATA phase interrupt later by setting everything
652*4882a593Smuzhiyun 		 * up ahead of time.
653*4882a593Smuzhiyun 		 */
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 		if ((cmd->SCp.phase == 0) && (hostdata->no_dma == 0)) {
656*4882a593Smuzhiyun 			if (hostdata->dma_setup(cmd,
657*4882a593Smuzhiyun 			    (cmd->sc_data_direction == DMA_TO_DEVICE) ?
658*4882a593Smuzhiyun 			     DATA_OUT_DIR : DATA_IN_DIR))
659*4882a593Smuzhiyun 				write_wd33c93_count(regs, 0);	/* guarantee a DATA_PHASE interrupt */
660*4882a593Smuzhiyun 			else {
661*4882a593Smuzhiyun 				write_wd33c93_count(regs,
662*4882a593Smuzhiyun 						    cmd->SCp.this_residual);
663*4882a593Smuzhiyun 				write_wd33c93(regs, WD_CONTROL,
664*4882a593Smuzhiyun 					      CTRL_IDI | CTRL_EDI | hostdata->dma_mode);
665*4882a593Smuzhiyun 				hostdata->dma = D_DMA_RUNNING;
666*4882a593Smuzhiyun 			}
667*4882a593Smuzhiyun 		} else
668*4882a593Smuzhiyun 			write_wd33c93_count(regs, 0);	/* guarantee a DATA_PHASE interrupt */
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 		hostdata->state = S_RUNNING_LEVEL2;
671*4882a593Smuzhiyun 		write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
672*4882a593Smuzhiyun 	}
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	/*
675*4882a593Smuzhiyun 	 * Since the SCSI bus can handle only 1 connection at a time,
676*4882a593Smuzhiyun 	 * we get out of here now. If the selection fails, or when
677*4882a593Smuzhiyun 	 * the command disconnects, we'll come back to this routine
678*4882a593Smuzhiyun 	 * to search the input_Q again...
679*4882a593Smuzhiyun 	 */
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	DB(DB_EXECUTE,
682*4882a593Smuzhiyun 	   printk("%s)EX-2 ", (cmd->SCp.phase) ? "d:" : ""))
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun static void
transfer_pio(const wd33c93_regs regs,uchar * buf,int cnt,int data_in_dir,struct WD33C93_hostdata * hostdata)686*4882a593Smuzhiyun transfer_pio(const wd33c93_regs regs, uchar * buf, int cnt,
687*4882a593Smuzhiyun 	     int data_in_dir, struct WD33C93_hostdata *hostdata)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun 	uchar asr;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	DB(DB_TRANSFER,
692*4882a593Smuzhiyun 	   printk("(%p,%d,%s:", buf, cnt, data_in_dir ? "in" : "out"))
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
695*4882a593Smuzhiyun 	write_wd33c93_count(regs, cnt);
696*4882a593Smuzhiyun 	write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO);
697*4882a593Smuzhiyun 	if (data_in_dir) {
698*4882a593Smuzhiyun 		do {
699*4882a593Smuzhiyun 			asr = read_aux_stat(regs);
700*4882a593Smuzhiyun 			if (asr & ASR_DBR)
701*4882a593Smuzhiyun 				*buf++ = read_wd33c93(regs, WD_DATA);
702*4882a593Smuzhiyun 		} while (!(asr & ASR_INT));
703*4882a593Smuzhiyun 	} else {
704*4882a593Smuzhiyun 		do {
705*4882a593Smuzhiyun 			asr = read_aux_stat(regs);
706*4882a593Smuzhiyun 			if (asr & ASR_DBR)
707*4882a593Smuzhiyun 				write_wd33c93(regs, WD_DATA, *buf++);
708*4882a593Smuzhiyun 		} while (!(asr & ASR_INT));
709*4882a593Smuzhiyun 	}
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	/* Note: we are returning with the interrupt UN-cleared.
712*4882a593Smuzhiyun 	 * Since (presumably) an entire I/O operation has
713*4882a593Smuzhiyun 	 * completed, the bus phase is probably different, and
714*4882a593Smuzhiyun 	 * the interrupt routine will discover this when it
715*4882a593Smuzhiyun 	 * responds to the uncleared int.
716*4882a593Smuzhiyun 	 */
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun static void
transfer_bytes(const wd33c93_regs regs,struct scsi_cmnd * cmd,int data_in_dir)721*4882a593Smuzhiyun transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
722*4882a593Smuzhiyun 		int data_in_dir)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun 	struct WD33C93_hostdata *hostdata;
725*4882a593Smuzhiyun 	unsigned long length;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun /* Normally, you'd expect 'this_residual' to be non-zero here.
730*4882a593Smuzhiyun  * In a series of scatter-gather transfers, however, this
731*4882a593Smuzhiyun  * routine will usually be called with 'this_residual' equal
732*4882a593Smuzhiyun  * to 0 and 'buffers_residual' non-zero. This means that a
733*4882a593Smuzhiyun  * previous transfer completed, clearing 'this_residual', and
734*4882a593Smuzhiyun  * now we need to setup the next scatter-gather buffer as the
735*4882a593Smuzhiyun  * source or destination for THIS transfer.
736*4882a593Smuzhiyun  */
737*4882a593Smuzhiyun 	if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
738*4882a593Smuzhiyun 		cmd->SCp.buffer = sg_next(cmd->SCp.buffer);
739*4882a593Smuzhiyun 		--cmd->SCp.buffers_residual;
740*4882a593Smuzhiyun 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
741*4882a593Smuzhiyun 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
742*4882a593Smuzhiyun 	}
743*4882a593Smuzhiyun 	if (!cmd->SCp.this_residual) /* avoid bogus setups */
744*4882a593Smuzhiyun 		return;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
747*4882a593Smuzhiyun 		      hostdata->sync_xfer[cmd->device->id]);
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun /* 'hostdata->no_dma' is TRUE if we don't even want to try DMA.
750*4882a593Smuzhiyun  * Update 'this_residual' and 'ptr' after 'transfer_pio()' returns.
751*4882a593Smuzhiyun  */
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	if (hostdata->no_dma || hostdata->dma_setup(cmd, data_in_dir)) {
754*4882a593Smuzhiyun #ifdef PROC_STATISTICS
755*4882a593Smuzhiyun 		hostdata->pio_cnt++;
756*4882a593Smuzhiyun #endif
757*4882a593Smuzhiyun 		transfer_pio(regs, (uchar *) cmd->SCp.ptr,
758*4882a593Smuzhiyun 			     cmd->SCp.this_residual, data_in_dir, hostdata);
759*4882a593Smuzhiyun 		length = cmd->SCp.this_residual;
760*4882a593Smuzhiyun 		cmd->SCp.this_residual = read_wd33c93_count(regs);
761*4882a593Smuzhiyun 		cmd->SCp.ptr += (length - cmd->SCp.this_residual);
762*4882a593Smuzhiyun 	}
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun /* We are able to do DMA (in fact, the Amiga hardware is
765*4882a593Smuzhiyun  * already going!), so start up the wd33c93 in DMA mode.
766*4882a593Smuzhiyun  * We set 'hostdata->dma' = D_DMA_RUNNING so that when the
767*4882a593Smuzhiyun  * transfer completes and causes an interrupt, we're
768*4882a593Smuzhiyun  * reminded to tell the Amiga to shut down its end. We'll
769*4882a593Smuzhiyun  * postpone the updating of 'this_residual' and 'ptr'
770*4882a593Smuzhiyun  * until then.
771*4882a593Smuzhiyun  */
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	else {
774*4882a593Smuzhiyun #ifdef PROC_STATISTICS
775*4882a593Smuzhiyun 		hostdata->dma_cnt++;
776*4882a593Smuzhiyun #endif
777*4882a593Smuzhiyun 		write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | hostdata->dma_mode);
778*4882a593Smuzhiyun 		write_wd33c93_count(regs, cmd->SCp.this_residual);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 		if ((hostdata->level2 >= L2_DATA) ||
781*4882a593Smuzhiyun 		    (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
782*4882a593Smuzhiyun 			write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);
783*4882a593Smuzhiyun 			write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
784*4882a593Smuzhiyun 			hostdata->state = S_RUNNING_LEVEL2;
785*4882a593Smuzhiyun 		} else
786*4882a593Smuzhiyun 			write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO);
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 		hostdata->dma = D_DMA_RUNNING;
789*4882a593Smuzhiyun 	}
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun void
wd33c93_intr(struct Scsi_Host * instance)793*4882a593Smuzhiyun wd33c93_intr(struct Scsi_Host *instance)
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun 	struct WD33C93_hostdata *hostdata =
796*4882a593Smuzhiyun 	    (struct WD33C93_hostdata *) instance->hostdata;
797*4882a593Smuzhiyun 	const wd33c93_regs regs = hostdata->regs;
798*4882a593Smuzhiyun 	struct scsi_cmnd *patch, *cmd;
799*4882a593Smuzhiyun 	uchar asr, sr, phs, id, lun, *ucp, msg;
800*4882a593Smuzhiyun 	unsigned long length, flags;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	asr = read_aux_stat(regs);
803*4882a593Smuzhiyun 	if (!(asr & ASR_INT) || (asr & ASR_BSY))
804*4882a593Smuzhiyun 		return;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	spin_lock_irqsave(&hostdata->lock, flags);
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun #ifdef PROC_STATISTICS
809*4882a593Smuzhiyun 	hostdata->int_cnt++;
810*4882a593Smuzhiyun #endif
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	cmd = (struct scsi_cmnd *) hostdata->connected;	/* assume we're connected */
813*4882a593Smuzhiyun 	sr = read_wd33c93(regs, WD_SCSI_STATUS);	/* clear the interrupt */
814*4882a593Smuzhiyun 	phs = read_wd33c93(regs, WD_COMMAND_PHASE);
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	DB(DB_INTR, printk("{%02x:%02x-", asr, sr))
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun /* After starting a DMA transfer, the next interrupt
819*4882a593Smuzhiyun  * is guaranteed to be in response to completion of
820*4882a593Smuzhiyun  * the transfer. Since the Amiga DMA hardware runs in
821*4882a593Smuzhiyun  * in an open-ended fashion, it needs to be told when
822*4882a593Smuzhiyun  * to stop; do that here if D_DMA_RUNNING is true.
823*4882a593Smuzhiyun  * Also, we have to update 'this_residual' and 'ptr'
824*4882a593Smuzhiyun  * based on the contents of the TRANSFER_COUNT register,
825*4882a593Smuzhiyun  * in case the device decided to do an intermediate
826*4882a593Smuzhiyun  * disconnect (a device may do this if it has to do a
827*4882a593Smuzhiyun  * seek, or just to be nice and let other devices have
828*4882a593Smuzhiyun  * some bus time during long transfers). After doing
829*4882a593Smuzhiyun  * whatever is needed, we go on and service the WD3393
830*4882a593Smuzhiyun  * interrupt normally.
831*4882a593Smuzhiyun  */
832*4882a593Smuzhiyun 	    if (hostdata->dma == D_DMA_RUNNING) {
833*4882a593Smuzhiyun 		DB(DB_TRANSFER,
834*4882a593Smuzhiyun 		   printk("[%p/%d:", cmd->SCp.ptr, cmd->SCp.this_residual))
835*4882a593Smuzhiyun 		    hostdata->dma_stop(cmd->device->host, cmd, 1);
836*4882a593Smuzhiyun 		hostdata->dma = D_DMA_OFF;
837*4882a593Smuzhiyun 		length = cmd->SCp.this_residual;
838*4882a593Smuzhiyun 		cmd->SCp.this_residual = read_wd33c93_count(regs);
839*4882a593Smuzhiyun 		cmd->SCp.ptr += (length - cmd->SCp.this_residual);
840*4882a593Smuzhiyun 		DB(DB_TRANSFER,
841*4882a593Smuzhiyun 		   printk("%p/%d]", cmd->SCp.ptr, cmd->SCp.this_residual))
842*4882a593Smuzhiyun 	}
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun /* Respond to the specific WD3393 interrupt - there are quite a few! */
845*4882a593Smuzhiyun 	switch (sr) {
846*4882a593Smuzhiyun 	case CSR_TIMEOUT:
847*4882a593Smuzhiyun 		DB(DB_INTR, printk("TIMEOUT"))
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 		    if (hostdata->state == S_RUNNING_LEVEL2)
850*4882a593Smuzhiyun 			hostdata->connected = NULL;
851*4882a593Smuzhiyun 		else {
852*4882a593Smuzhiyun 			cmd = (struct scsi_cmnd *) hostdata->selecting;	/* get a valid cmd */
853*4882a593Smuzhiyun 			hostdata->selecting = NULL;
854*4882a593Smuzhiyun 		}
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 		cmd->result = DID_NO_CONNECT << 16;
857*4882a593Smuzhiyun 		hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xff));
858*4882a593Smuzhiyun 		hostdata->state = S_UNCONNECTED;
859*4882a593Smuzhiyun 		cmd->scsi_done(cmd);
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 		/* From esp.c:
862*4882a593Smuzhiyun 		 * There is a window of time within the scsi_done() path
863*4882a593Smuzhiyun 		 * of execution where interrupts are turned back on full
864*4882a593Smuzhiyun 		 * blast and left that way.  During that time we could
865*4882a593Smuzhiyun 		 * reconnect to a disconnected command, then we'd bomb
866*4882a593Smuzhiyun 		 * out below.  We could also end up executing two commands
867*4882a593Smuzhiyun 		 * at _once_.  ...just so you know why the restore_flags()
868*4882a593Smuzhiyun 		 * is here...
869*4882a593Smuzhiyun 		 */
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun /* We are not connected to a target - check to see if there
874*4882a593Smuzhiyun  * are commands waiting to be executed.
875*4882a593Smuzhiyun  */
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 		wd33c93_execute(instance);
878*4882a593Smuzhiyun 		break;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun /* Note: this interrupt should not occur in a LEVEL2 command */
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	case CSR_SELECT:
883*4882a593Smuzhiyun 		DB(DB_INTR, printk("SELECT"))
884*4882a593Smuzhiyun 		    hostdata->connected = cmd =
885*4882a593Smuzhiyun 		    (struct scsi_cmnd *) hostdata->selecting;
886*4882a593Smuzhiyun 		hostdata->selecting = NULL;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 		/* construct an IDENTIFY message with correct disconnect bit */
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 		hostdata->outgoing_msg[0] = IDENTIFY(0, cmd->device->lun);
891*4882a593Smuzhiyun 		if (cmd->SCp.phase)
892*4882a593Smuzhiyun 			hostdata->outgoing_msg[0] |= 0x40;
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 		if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) {
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 			hostdata->sync_stat[cmd->device->id] = SS_WAITING;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun /* Tack on a 2nd message to ask about synchronous transfers. If we've
899*4882a593Smuzhiyun  * been asked to do only asynchronous transfers on this device, we
900*4882a593Smuzhiyun  * request a fifo depth of 0, which is equivalent to async - should
901*4882a593Smuzhiyun  * solve the problems some people have had with GVP's Guru ROM.
902*4882a593Smuzhiyun  */
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 			hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
905*4882a593Smuzhiyun 			hostdata->outgoing_msg[2] = 3;
906*4882a593Smuzhiyun 			hostdata->outgoing_msg[3] = EXTENDED_SDTR;
907*4882a593Smuzhiyun 			if (hostdata->no_sync & (1 << cmd->device->id)) {
908*4882a593Smuzhiyun 				calc_sync_msg(hostdata->default_sx_per, 0,
909*4882a593Smuzhiyun 						0, hostdata->outgoing_msg + 4);
910*4882a593Smuzhiyun 			} else {
911*4882a593Smuzhiyun 				calc_sync_msg(optimum_sx_per(hostdata),
912*4882a593Smuzhiyun 						OPTIMUM_SX_OFF,
913*4882a593Smuzhiyun 						hostdata->fast,
914*4882a593Smuzhiyun 						hostdata->outgoing_msg + 4);
915*4882a593Smuzhiyun 			}
916*4882a593Smuzhiyun 			hostdata->outgoing_len = 6;
917*4882a593Smuzhiyun #ifdef SYNC_DEBUG
918*4882a593Smuzhiyun 			ucp = hostdata->outgoing_msg + 1;
919*4882a593Smuzhiyun 			printk(" sending SDTR %02x03%02x%02x%02x ",
920*4882a593Smuzhiyun 				ucp[0], ucp[2], ucp[3], ucp[4]);
921*4882a593Smuzhiyun #endif
922*4882a593Smuzhiyun 		} else
923*4882a593Smuzhiyun 			hostdata->outgoing_len = 1;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 		hostdata->state = S_CONNECTED;
926*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
927*4882a593Smuzhiyun 		break;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	case CSR_XFER_DONE | PHS_DATA_IN:
930*4882a593Smuzhiyun 	case CSR_UNEXP | PHS_DATA_IN:
931*4882a593Smuzhiyun 	case CSR_SRV_REQ | PHS_DATA_IN:
932*4882a593Smuzhiyun 		DB(DB_INTR,
933*4882a593Smuzhiyun 		   printk("IN-%d.%d", cmd->SCp.this_residual,
934*4882a593Smuzhiyun 			  cmd->SCp.buffers_residual))
935*4882a593Smuzhiyun 		    transfer_bytes(regs, cmd, DATA_IN_DIR);
936*4882a593Smuzhiyun 		if (hostdata->state != S_RUNNING_LEVEL2)
937*4882a593Smuzhiyun 			hostdata->state = S_CONNECTED;
938*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
939*4882a593Smuzhiyun 		break;
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	case CSR_XFER_DONE | PHS_DATA_OUT:
942*4882a593Smuzhiyun 	case CSR_UNEXP | PHS_DATA_OUT:
943*4882a593Smuzhiyun 	case CSR_SRV_REQ | PHS_DATA_OUT:
944*4882a593Smuzhiyun 		DB(DB_INTR,
945*4882a593Smuzhiyun 		   printk("OUT-%d.%d", cmd->SCp.this_residual,
946*4882a593Smuzhiyun 			  cmd->SCp.buffers_residual))
947*4882a593Smuzhiyun 		    transfer_bytes(regs, cmd, DATA_OUT_DIR);
948*4882a593Smuzhiyun 		if (hostdata->state != S_RUNNING_LEVEL2)
949*4882a593Smuzhiyun 			hostdata->state = S_CONNECTED;
950*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
951*4882a593Smuzhiyun 		break;
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun /* Note: this interrupt should not occur in a LEVEL2 command */
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	case CSR_XFER_DONE | PHS_COMMAND:
956*4882a593Smuzhiyun 	case CSR_UNEXP | PHS_COMMAND:
957*4882a593Smuzhiyun 	case CSR_SRV_REQ | PHS_COMMAND:
958*4882a593Smuzhiyun 		DB(DB_INTR, printk("CMND-%02x", cmd->cmnd[0]))
959*4882a593Smuzhiyun 		    transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR,
960*4882a593Smuzhiyun 				 hostdata);
961*4882a593Smuzhiyun 		hostdata->state = S_CONNECTED;
962*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
963*4882a593Smuzhiyun 		break;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	case CSR_XFER_DONE | PHS_STATUS:
966*4882a593Smuzhiyun 	case CSR_UNEXP | PHS_STATUS:
967*4882a593Smuzhiyun 	case CSR_SRV_REQ | PHS_STATUS:
968*4882a593Smuzhiyun 		DB(DB_INTR, printk("STATUS="))
969*4882a593Smuzhiyun 		cmd->SCp.Status = read_1_byte(regs);
970*4882a593Smuzhiyun 		DB(DB_INTR, printk("%02x", cmd->SCp.Status))
971*4882a593Smuzhiyun 		    if (hostdata->level2 >= L2_BASIC) {
972*4882a593Smuzhiyun 			sr = read_wd33c93(regs, WD_SCSI_STATUS);	/* clear interrupt */
973*4882a593Smuzhiyun 			udelay(7);
974*4882a593Smuzhiyun 			hostdata->state = S_RUNNING_LEVEL2;
975*4882a593Smuzhiyun 			write_wd33c93(regs, WD_COMMAND_PHASE, 0x50);
976*4882a593Smuzhiyun 			write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
977*4882a593Smuzhiyun 		} else {
978*4882a593Smuzhiyun 			hostdata->state = S_CONNECTED;
979*4882a593Smuzhiyun 		}
980*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
981*4882a593Smuzhiyun 		break;
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	case CSR_XFER_DONE | PHS_MESS_IN:
984*4882a593Smuzhiyun 	case CSR_UNEXP | PHS_MESS_IN:
985*4882a593Smuzhiyun 	case CSR_SRV_REQ | PHS_MESS_IN:
986*4882a593Smuzhiyun 		DB(DB_INTR, printk("MSG_IN="))
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 		msg = read_1_byte(regs);
989*4882a593Smuzhiyun 		sr = read_wd33c93(regs, WD_SCSI_STATUS);	/* clear interrupt */
990*4882a593Smuzhiyun 		udelay(7);
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 		hostdata->incoming_msg[hostdata->incoming_ptr] = msg;
993*4882a593Smuzhiyun 		if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)
994*4882a593Smuzhiyun 			msg = EXTENDED_MESSAGE;
995*4882a593Smuzhiyun 		else
996*4882a593Smuzhiyun 			hostdata->incoming_ptr = 0;
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 		cmd->SCp.Message = msg;
999*4882a593Smuzhiyun 		switch (msg) {
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 		case COMMAND_COMPLETE:
1002*4882a593Smuzhiyun 			DB(DB_INTR, printk("CCMP"))
1003*4882a593Smuzhiyun 			    write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
1004*4882a593Smuzhiyun 			hostdata->state = S_PRE_CMP_DISC;
1005*4882a593Smuzhiyun 			break;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 		case SAVE_POINTERS:
1008*4882a593Smuzhiyun 			DB(DB_INTR, printk("SDP"))
1009*4882a593Smuzhiyun 			    write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
1010*4882a593Smuzhiyun 			hostdata->state = S_CONNECTED;
1011*4882a593Smuzhiyun 			break;
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun 		case RESTORE_POINTERS:
1014*4882a593Smuzhiyun 			DB(DB_INTR, printk("RDP"))
1015*4882a593Smuzhiyun 			    if (hostdata->level2 >= L2_BASIC) {
1016*4882a593Smuzhiyun 				write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);
1017*4882a593Smuzhiyun 				write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
1018*4882a593Smuzhiyun 				hostdata->state = S_RUNNING_LEVEL2;
1019*4882a593Smuzhiyun 			} else {
1020*4882a593Smuzhiyun 				write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
1021*4882a593Smuzhiyun 				hostdata->state = S_CONNECTED;
1022*4882a593Smuzhiyun 			}
1023*4882a593Smuzhiyun 			break;
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 		case DISCONNECT:
1026*4882a593Smuzhiyun 			DB(DB_INTR, printk("DIS"))
1027*4882a593Smuzhiyun 			    cmd->device->disconnect = 1;
1028*4882a593Smuzhiyun 			write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
1029*4882a593Smuzhiyun 			hostdata->state = S_PRE_TMP_DISC;
1030*4882a593Smuzhiyun 			break;
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 		case MESSAGE_REJECT:
1033*4882a593Smuzhiyun 			DB(DB_INTR, printk("REJ"))
1034*4882a593Smuzhiyun #ifdef SYNC_DEBUG
1035*4882a593Smuzhiyun 			    printk("-REJ-");
1036*4882a593Smuzhiyun #endif
1037*4882a593Smuzhiyun 			if (hostdata->sync_stat[cmd->device->id] == SS_WAITING) {
1038*4882a593Smuzhiyun 				hostdata->sync_stat[cmd->device->id] = SS_SET;
1039*4882a593Smuzhiyun 				/* we want default_sx_per, not DEFAULT_SX_PER */
1040*4882a593Smuzhiyun 				hostdata->sync_xfer[cmd->device->id] =
1041*4882a593Smuzhiyun 					calc_sync_xfer(hostdata->default_sx_per
1042*4882a593Smuzhiyun 						/ 4, 0, 0, hostdata->sx_table);
1043*4882a593Smuzhiyun 			}
1044*4882a593Smuzhiyun 			write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
1045*4882a593Smuzhiyun 			hostdata->state = S_CONNECTED;
1046*4882a593Smuzhiyun 			break;
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 		case EXTENDED_MESSAGE:
1049*4882a593Smuzhiyun 			DB(DB_INTR, printk("EXT"))
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 			    ucp = hostdata->incoming_msg;
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun #ifdef SYNC_DEBUG
1054*4882a593Smuzhiyun 			printk("%02x", ucp[hostdata->incoming_ptr]);
1055*4882a593Smuzhiyun #endif
1056*4882a593Smuzhiyun 			/* Is this the last byte of the extended message? */
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun 			if ((hostdata->incoming_ptr >= 2) &&
1059*4882a593Smuzhiyun 			    (hostdata->incoming_ptr == (ucp[1] + 1))) {
1060*4882a593Smuzhiyun 
1061*4882a593Smuzhiyun 				switch (ucp[2]) {	/* what's the EXTENDED code? */
1062*4882a593Smuzhiyun 				case EXTENDED_SDTR:
1063*4882a593Smuzhiyun 					/* default to default async period */
1064*4882a593Smuzhiyun 					id = calc_sync_xfer(hostdata->
1065*4882a593Smuzhiyun 							default_sx_per / 4, 0,
1066*4882a593Smuzhiyun 							0, hostdata->sx_table);
1067*4882a593Smuzhiyun 					if (hostdata->sync_stat[cmd->device->id] !=
1068*4882a593Smuzhiyun 					    SS_WAITING) {
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun /* A device has sent an unsolicited SDTR message; rather than go
1071*4882a593Smuzhiyun  * through the effort of decoding it and then figuring out what
1072*4882a593Smuzhiyun  * our reply should be, we're just gonna say that we have a
1073*4882a593Smuzhiyun  * synchronous fifo depth of 0. This will result in asynchronous
1074*4882a593Smuzhiyun  * transfers - not ideal but so much easier.
1075*4882a593Smuzhiyun  * Actually, this is OK because it assures us that if we don't
1076*4882a593Smuzhiyun  * specifically ask for sync transfers, we won't do any.
1077*4882a593Smuzhiyun  */
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 						write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
1080*4882a593Smuzhiyun 						hostdata->outgoing_msg[0] =
1081*4882a593Smuzhiyun 						    EXTENDED_MESSAGE;
1082*4882a593Smuzhiyun 						hostdata->outgoing_msg[1] = 3;
1083*4882a593Smuzhiyun 						hostdata->outgoing_msg[2] =
1084*4882a593Smuzhiyun 						    EXTENDED_SDTR;
1085*4882a593Smuzhiyun 						calc_sync_msg(hostdata->
1086*4882a593Smuzhiyun 							default_sx_per, 0,
1087*4882a593Smuzhiyun 							0, hostdata->outgoing_msg + 3);
1088*4882a593Smuzhiyun 						hostdata->outgoing_len = 5;
1089*4882a593Smuzhiyun 					} else {
1090*4882a593Smuzhiyun 						if (ucp[4]) /* well, sync transfer */
1091*4882a593Smuzhiyun 							id = calc_sync_xfer(ucp[3], ucp[4],
1092*4882a593Smuzhiyun 									hostdata->fast,
1093*4882a593Smuzhiyun 									hostdata->sx_table);
1094*4882a593Smuzhiyun 						else if (ucp[3]) /* very unlikely... */
1095*4882a593Smuzhiyun 							id = calc_sync_xfer(ucp[3], ucp[4],
1096*4882a593Smuzhiyun 									0, hostdata->sx_table);
1097*4882a593Smuzhiyun 					}
1098*4882a593Smuzhiyun 					hostdata->sync_xfer[cmd->device->id] = id;
1099*4882a593Smuzhiyun #ifdef SYNC_DEBUG
1100*4882a593Smuzhiyun 					printk(" sync_xfer=%02x\n",
1101*4882a593Smuzhiyun 					       hostdata->sync_xfer[cmd->device->id]);
1102*4882a593Smuzhiyun #endif
1103*4882a593Smuzhiyun 					hostdata->sync_stat[cmd->device->id] =
1104*4882a593Smuzhiyun 					    SS_SET;
1105*4882a593Smuzhiyun 					write_wd33c93_cmd(regs,
1106*4882a593Smuzhiyun 							  WD_CMD_NEGATE_ACK);
1107*4882a593Smuzhiyun 					hostdata->state = S_CONNECTED;
1108*4882a593Smuzhiyun 					break;
1109*4882a593Smuzhiyun 				case EXTENDED_WDTR:
1110*4882a593Smuzhiyun 					write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
1111*4882a593Smuzhiyun 					printk("sending WDTR ");
1112*4882a593Smuzhiyun 					hostdata->outgoing_msg[0] =
1113*4882a593Smuzhiyun 					    EXTENDED_MESSAGE;
1114*4882a593Smuzhiyun 					hostdata->outgoing_msg[1] = 2;
1115*4882a593Smuzhiyun 					hostdata->outgoing_msg[2] =
1116*4882a593Smuzhiyun 					    EXTENDED_WDTR;
1117*4882a593Smuzhiyun 					hostdata->outgoing_msg[3] = 0;	/* 8 bit transfer width */
1118*4882a593Smuzhiyun 					hostdata->outgoing_len = 4;
1119*4882a593Smuzhiyun 					write_wd33c93_cmd(regs,
1120*4882a593Smuzhiyun 							  WD_CMD_NEGATE_ACK);
1121*4882a593Smuzhiyun 					hostdata->state = S_CONNECTED;
1122*4882a593Smuzhiyun 					break;
1123*4882a593Smuzhiyun 				default:
1124*4882a593Smuzhiyun 					write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
1125*4882a593Smuzhiyun 					printk
1126*4882a593Smuzhiyun 					    ("Rejecting Unknown Extended Message(%02x). ",
1127*4882a593Smuzhiyun 					     ucp[2]);
1128*4882a593Smuzhiyun 					hostdata->outgoing_msg[0] =
1129*4882a593Smuzhiyun 					    MESSAGE_REJECT;
1130*4882a593Smuzhiyun 					hostdata->outgoing_len = 1;
1131*4882a593Smuzhiyun 					write_wd33c93_cmd(regs,
1132*4882a593Smuzhiyun 							  WD_CMD_NEGATE_ACK);
1133*4882a593Smuzhiyun 					hostdata->state = S_CONNECTED;
1134*4882a593Smuzhiyun 					break;
1135*4882a593Smuzhiyun 				}
1136*4882a593Smuzhiyun 				hostdata->incoming_ptr = 0;
1137*4882a593Smuzhiyun 			}
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 			/* We need to read more MESS_IN bytes for the extended message */
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 			else {
1142*4882a593Smuzhiyun 				hostdata->incoming_ptr++;
1143*4882a593Smuzhiyun 				write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
1144*4882a593Smuzhiyun 				hostdata->state = S_CONNECTED;
1145*4882a593Smuzhiyun 			}
1146*4882a593Smuzhiyun 			break;
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun 		default:
1149*4882a593Smuzhiyun 			printk("Rejecting Unknown Message(%02x) ", msg);
1150*4882a593Smuzhiyun 			write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
1151*4882a593Smuzhiyun 			hostdata->outgoing_msg[0] = MESSAGE_REJECT;
1152*4882a593Smuzhiyun 			hostdata->outgoing_len = 1;
1153*4882a593Smuzhiyun 			write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
1154*4882a593Smuzhiyun 			hostdata->state = S_CONNECTED;
1155*4882a593Smuzhiyun 		}
1156*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
1157*4882a593Smuzhiyun 		break;
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun /* Note: this interrupt will occur only after a LEVEL2 command */
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	case CSR_SEL_XFER_DONE:
1162*4882a593Smuzhiyun 
1163*4882a593Smuzhiyun /* Make sure that reselection is enabled at this point - it may
1164*4882a593Smuzhiyun  * have been turned off for the command that just completed.
1165*4882a593Smuzhiyun  */
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 		write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
1168*4882a593Smuzhiyun 		if (phs == 0x60) {
1169*4882a593Smuzhiyun 			DB(DB_INTR, printk("SX-DONE"))
1170*4882a593Smuzhiyun 			    cmd->SCp.Message = COMMAND_COMPLETE;
1171*4882a593Smuzhiyun 			lun = read_wd33c93(regs, WD_TARGET_LUN);
1172*4882a593Smuzhiyun 			DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
1173*4882a593Smuzhiyun 			    hostdata->connected = NULL;
1174*4882a593Smuzhiyun 			hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xff));
1175*4882a593Smuzhiyun 			hostdata->state = S_UNCONNECTED;
1176*4882a593Smuzhiyun 			if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
1177*4882a593Smuzhiyun 				cmd->SCp.Status = lun;
1178*4882a593Smuzhiyun 			if (cmd->cmnd[0] == REQUEST_SENSE
1179*4882a593Smuzhiyun 			    && cmd->SCp.Status != GOOD)
1180*4882a593Smuzhiyun 				cmd->result =
1181*4882a593Smuzhiyun 				    (cmd->
1182*4882a593Smuzhiyun 				     result & 0x00ffff) | (DID_ERROR << 16);
1183*4882a593Smuzhiyun 			else
1184*4882a593Smuzhiyun 				cmd->result =
1185*4882a593Smuzhiyun 				    cmd->SCp.Status | (cmd->SCp.Message << 8);
1186*4882a593Smuzhiyun 			cmd->scsi_done(cmd);
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun /* We are no longer  connected to a target - check to see if
1189*4882a593Smuzhiyun  * there are commands waiting to be executed.
1190*4882a593Smuzhiyun  */
1191*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hostdata->lock, flags);
1192*4882a593Smuzhiyun 			wd33c93_execute(instance);
1193*4882a593Smuzhiyun 		} else {
1194*4882a593Smuzhiyun 			printk
1195*4882a593Smuzhiyun 			    ("%02x:%02x:%02x: Unknown SEL_XFER_DONE phase!!---",
1196*4882a593Smuzhiyun 			     asr, sr, phs);
1197*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hostdata->lock, flags);
1198*4882a593Smuzhiyun 		}
1199*4882a593Smuzhiyun 		break;
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun /* Note: this interrupt will occur only after a LEVEL2 command */
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	case CSR_SDP:
1204*4882a593Smuzhiyun 		DB(DB_INTR, printk("SDP"))
1205*4882a593Smuzhiyun 		    hostdata->state = S_RUNNING_LEVEL2;
1206*4882a593Smuzhiyun 		write_wd33c93(regs, WD_COMMAND_PHASE, 0x41);
1207*4882a593Smuzhiyun 		write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
1208*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
1209*4882a593Smuzhiyun 		break;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	case CSR_XFER_DONE | PHS_MESS_OUT:
1212*4882a593Smuzhiyun 	case CSR_UNEXP | PHS_MESS_OUT:
1213*4882a593Smuzhiyun 	case CSR_SRV_REQ | PHS_MESS_OUT:
1214*4882a593Smuzhiyun 		DB(DB_INTR, printk("MSG_OUT="))
1215*4882a593Smuzhiyun 
1216*4882a593Smuzhiyun /* To get here, we've probably requested MESSAGE_OUT and have
1217*4882a593Smuzhiyun  * already put the correct bytes in outgoing_msg[] and filled
1218*4882a593Smuzhiyun  * in outgoing_len. We simply send them out to the SCSI bus.
1219*4882a593Smuzhiyun  * Sometimes we get MESSAGE_OUT phase when we're not expecting
1220*4882a593Smuzhiyun  * it - like when our SDTR message is rejected by a target. Some
1221*4882a593Smuzhiyun  * targets send the REJECT before receiving all of the extended
1222*4882a593Smuzhiyun  * message, and then seem to go back to MESSAGE_OUT for a byte
1223*4882a593Smuzhiyun  * or two. Not sure why, or if I'm doing something wrong to
1224*4882a593Smuzhiyun  * cause this to happen. Regardless, it seems that sending
1225*4882a593Smuzhiyun  * NOP messages in these situations results in no harm and
1226*4882a593Smuzhiyun  * makes everyone happy.
1227*4882a593Smuzhiyun  */
1228*4882a593Smuzhiyun 		    if (hostdata->outgoing_len == 0) {
1229*4882a593Smuzhiyun 			hostdata->outgoing_len = 1;
1230*4882a593Smuzhiyun 			hostdata->outgoing_msg[0] = NOP;
1231*4882a593Smuzhiyun 		}
1232*4882a593Smuzhiyun 		transfer_pio(regs, hostdata->outgoing_msg,
1233*4882a593Smuzhiyun 			     hostdata->outgoing_len, DATA_OUT_DIR, hostdata);
1234*4882a593Smuzhiyun 		DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0]))
1235*4882a593Smuzhiyun 		    hostdata->outgoing_len = 0;
1236*4882a593Smuzhiyun 		hostdata->state = S_CONNECTED;
1237*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
1238*4882a593Smuzhiyun 		break;
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun 	case CSR_UNEXP_DISC:
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun /* I think I've seen this after a request-sense that was in response
1243*4882a593Smuzhiyun  * to an error condition, but not sure. We certainly need to do
1244*4882a593Smuzhiyun  * something when we get this interrupt - the question is 'what?'.
1245*4882a593Smuzhiyun  * Let's think positively, and assume some command has finished
1246*4882a593Smuzhiyun  * in a legal manner (like a command that provokes a request-sense),
1247*4882a593Smuzhiyun  * so we treat it as a normal command-complete-disconnect.
1248*4882a593Smuzhiyun  */
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun /* Make sure that reselection is enabled at this point - it may
1251*4882a593Smuzhiyun  * have been turned off for the command that just completed.
1252*4882a593Smuzhiyun  */
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun 		write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
1255*4882a593Smuzhiyun 		if (cmd == NULL) {
1256*4882a593Smuzhiyun 			printk(" - Already disconnected! ");
1257*4882a593Smuzhiyun 			hostdata->state = S_UNCONNECTED;
1258*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hostdata->lock, flags);
1259*4882a593Smuzhiyun 			return;
1260*4882a593Smuzhiyun 		}
1261*4882a593Smuzhiyun 		DB(DB_INTR, printk("UNEXP_DISC"))
1262*4882a593Smuzhiyun 		    hostdata->connected = NULL;
1263*4882a593Smuzhiyun 		hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xff));
1264*4882a593Smuzhiyun 		hostdata->state = S_UNCONNECTED;
1265*4882a593Smuzhiyun 		if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
1266*4882a593Smuzhiyun 			cmd->result =
1267*4882a593Smuzhiyun 			    (cmd->result & 0x00ffff) | (DID_ERROR << 16);
1268*4882a593Smuzhiyun 		else
1269*4882a593Smuzhiyun 			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
1270*4882a593Smuzhiyun 		cmd->scsi_done(cmd);
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun /* We are no longer connected to a target - check to see if
1273*4882a593Smuzhiyun  * there are commands waiting to be executed.
1274*4882a593Smuzhiyun  */
1275*4882a593Smuzhiyun 		/* look above for comments on scsi_done() */
1276*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
1277*4882a593Smuzhiyun 		wd33c93_execute(instance);
1278*4882a593Smuzhiyun 		break;
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun 	case CSR_DISC:
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun /* Make sure that reselection is enabled at this point - it may
1283*4882a593Smuzhiyun  * have been turned off for the command that just completed.
1284*4882a593Smuzhiyun  */
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 		write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
1287*4882a593Smuzhiyun 		DB(DB_INTR, printk("DISC"))
1288*4882a593Smuzhiyun 		    if (cmd == NULL) {
1289*4882a593Smuzhiyun 			printk(" - Already disconnected! ");
1290*4882a593Smuzhiyun 			hostdata->state = S_UNCONNECTED;
1291*4882a593Smuzhiyun 		}
1292*4882a593Smuzhiyun 		switch (hostdata->state) {
1293*4882a593Smuzhiyun 		case S_PRE_CMP_DISC:
1294*4882a593Smuzhiyun 			hostdata->connected = NULL;
1295*4882a593Smuzhiyun 			hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xff));
1296*4882a593Smuzhiyun 			hostdata->state = S_UNCONNECTED;
1297*4882a593Smuzhiyun 			DB(DB_INTR, printk(":%d", cmd->SCp.Status))
1298*4882a593Smuzhiyun 			    if (cmd->cmnd[0] == REQUEST_SENSE
1299*4882a593Smuzhiyun 				&& cmd->SCp.Status != GOOD)
1300*4882a593Smuzhiyun 				cmd->result =
1301*4882a593Smuzhiyun 				    (cmd->
1302*4882a593Smuzhiyun 				     result & 0x00ffff) | (DID_ERROR << 16);
1303*4882a593Smuzhiyun 			else
1304*4882a593Smuzhiyun 				cmd->result =
1305*4882a593Smuzhiyun 				    cmd->SCp.Status | (cmd->SCp.Message << 8);
1306*4882a593Smuzhiyun 			cmd->scsi_done(cmd);
1307*4882a593Smuzhiyun 			break;
1308*4882a593Smuzhiyun 		case S_PRE_TMP_DISC:
1309*4882a593Smuzhiyun 		case S_RUNNING_LEVEL2:
1310*4882a593Smuzhiyun 			cmd->host_scribble = (uchar *) hostdata->disconnected_Q;
1311*4882a593Smuzhiyun 			hostdata->disconnected_Q = cmd;
1312*4882a593Smuzhiyun 			hostdata->connected = NULL;
1313*4882a593Smuzhiyun 			hostdata->state = S_UNCONNECTED;
1314*4882a593Smuzhiyun 
1315*4882a593Smuzhiyun #ifdef PROC_STATISTICS
1316*4882a593Smuzhiyun 			hostdata->disc_done_cnt[cmd->device->id]++;
1317*4882a593Smuzhiyun #endif
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 			break;
1320*4882a593Smuzhiyun 		default:
1321*4882a593Smuzhiyun 			printk("*** Unexpected DISCONNECT interrupt! ***");
1322*4882a593Smuzhiyun 			hostdata->state = S_UNCONNECTED;
1323*4882a593Smuzhiyun 		}
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun /* We are no longer connected to a target - check to see if
1326*4882a593Smuzhiyun  * there are commands waiting to be executed.
1327*4882a593Smuzhiyun  */
1328*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
1329*4882a593Smuzhiyun 		wd33c93_execute(instance);
1330*4882a593Smuzhiyun 		break;
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun 	case CSR_RESEL_AM:
1333*4882a593Smuzhiyun 	case CSR_RESEL:
1334*4882a593Smuzhiyun 		DB(DB_INTR, printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
1335*4882a593Smuzhiyun 
1336*4882a593Smuzhiyun 		    /* Old chips (pre -A ???) don't have advanced features and will
1337*4882a593Smuzhiyun 		     * generate CSR_RESEL.  In that case we have to extract the LUN the
1338*4882a593Smuzhiyun 		     * hard way (see below).
1339*4882a593Smuzhiyun 		     * First we have to make sure this reselection didn't
1340*4882a593Smuzhiyun 		     * happen during Arbitration/Selection of some other device.
1341*4882a593Smuzhiyun 		     * If yes, put losing command back on top of input_Q.
1342*4882a593Smuzhiyun 		     */
1343*4882a593Smuzhiyun 		    if (hostdata->level2 <= L2_NONE) {
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun 			if (hostdata->selecting) {
1346*4882a593Smuzhiyun 				cmd = (struct scsi_cmnd *) hostdata->selecting;
1347*4882a593Smuzhiyun 				hostdata->selecting = NULL;
1348*4882a593Smuzhiyun 				hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xff));
1349*4882a593Smuzhiyun 				cmd->host_scribble =
1350*4882a593Smuzhiyun 				    (uchar *) hostdata->input_Q;
1351*4882a593Smuzhiyun 				hostdata->input_Q = cmd;
1352*4882a593Smuzhiyun 			}
1353*4882a593Smuzhiyun 		}
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun 		else {
1356*4882a593Smuzhiyun 
1357*4882a593Smuzhiyun 			if (cmd) {
1358*4882a593Smuzhiyun 				if (phs == 0x00) {
1359*4882a593Smuzhiyun 					hostdata->busy[cmd->device->id] &=
1360*4882a593Smuzhiyun 						~(1 << (cmd->device->lun & 0xff));
1361*4882a593Smuzhiyun 					cmd->host_scribble =
1362*4882a593Smuzhiyun 					    (uchar *) hostdata->input_Q;
1363*4882a593Smuzhiyun 					hostdata->input_Q = cmd;
1364*4882a593Smuzhiyun 				} else {
1365*4882a593Smuzhiyun 					printk
1366*4882a593Smuzhiyun 					    ("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",
1367*4882a593Smuzhiyun 					     asr, sr, phs);
1368*4882a593Smuzhiyun 					while (1)
1369*4882a593Smuzhiyun 						printk("\r");
1370*4882a593Smuzhiyun 				}
1371*4882a593Smuzhiyun 			}
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 		}
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun 		/* OK - find out which device reselected us. */
1376*4882a593Smuzhiyun 
1377*4882a593Smuzhiyun 		id = read_wd33c93(regs, WD_SOURCE_ID);
1378*4882a593Smuzhiyun 		id &= SRCID_MASK;
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun 		/* and extract the lun from the ID message. (Note that we don't
1381*4882a593Smuzhiyun 		 * bother to check for a valid message here - I guess this is
1382*4882a593Smuzhiyun 		 * not the right way to go, but...)
1383*4882a593Smuzhiyun 		 */
1384*4882a593Smuzhiyun 
1385*4882a593Smuzhiyun 		if (sr == CSR_RESEL_AM) {
1386*4882a593Smuzhiyun 			lun = read_wd33c93(regs, WD_DATA);
1387*4882a593Smuzhiyun 			if (hostdata->level2 < L2_RESELECT)
1388*4882a593Smuzhiyun 				write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
1389*4882a593Smuzhiyun 			lun &= 7;
1390*4882a593Smuzhiyun 		} else {
1391*4882a593Smuzhiyun 			/* Old chip; wait for msgin phase to pick up the LUN. */
1392*4882a593Smuzhiyun 			for (lun = 255; lun; lun--) {
1393*4882a593Smuzhiyun 				if ((asr = read_aux_stat(regs)) & ASR_INT)
1394*4882a593Smuzhiyun 					break;
1395*4882a593Smuzhiyun 				udelay(10);
1396*4882a593Smuzhiyun 			}
1397*4882a593Smuzhiyun 			if (!(asr & ASR_INT)) {
1398*4882a593Smuzhiyun 				printk
1399*4882a593Smuzhiyun 				    ("wd33c93: Reselected without IDENTIFY\n");
1400*4882a593Smuzhiyun 				lun = 0;
1401*4882a593Smuzhiyun 			} else {
1402*4882a593Smuzhiyun 				/* Verify this is a change to MSG_IN and read the message */
1403*4882a593Smuzhiyun 				sr = read_wd33c93(regs, WD_SCSI_STATUS);
1404*4882a593Smuzhiyun 				udelay(7);
1405*4882a593Smuzhiyun 				if (sr == (CSR_ABORT | PHS_MESS_IN) ||
1406*4882a593Smuzhiyun 				    sr == (CSR_UNEXP | PHS_MESS_IN) ||
1407*4882a593Smuzhiyun 				    sr == (CSR_SRV_REQ | PHS_MESS_IN)) {
1408*4882a593Smuzhiyun 					/* Got MSG_IN, grab target LUN */
1409*4882a593Smuzhiyun 					lun = read_1_byte(regs);
1410*4882a593Smuzhiyun 					/* Now we expect a 'paused with ACK asserted' int.. */
1411*4882a593Smuzhiyun 					asr = read_aux_stat(regs);
1412*4882a593Smuzhiyun 					if (!(asr & ASR_INT)) {
1413*4882a593Smuzhiyun 						udelay(10);
1414*4882a593Smuzhiyun 						asr = read_aux_stat(regs);
1415*4882a593Smuzhiyun 						if (!(asr & ASR_INT))
1416*4882a593Smuzhiyun 							printk
1417*4882a593Smuzhiyun 							    ("wd33c93: No int after LUN on RESEL (%02x)\n",
1418*4882a593Smuzhiyun 							     asr);
1419*4882a593Smuzhiyun 					}
1420*4882a593Smuzhiyun 					sr = read_wd33c93(regs, WD_SCSI_STATUS);
1421*4882a593Smuzhiyun 					udelay(7);
1422*4882a593Smuzhiyun 					if (sr != CSR_MSGIN)
1423*4882a593Smuzhiyun 						printk
1424*4882a593Smuzhiyun 						    ("wd33c93: Not paused with ACK on RESEL (%02x)\n",
1425*4882a593Smuzhiyun 						     sr);
1426*4882a593Smuzhiyun 					lun &= 7;
1427*4882a593Smuzhiyun 					write_wd33c93_cmd(regs,
1428*4882a593Smuzhiyun 							  WD_CMD_NEGATE_ACK);
1429*4882a593Smuzhiyun 				} else {
1430*4882a593Smuzhiyun 					printk
1431*4882a593Smuzhiyun 					    ("wd33c93: Not MSG_IN on reselect (%02x)\n",
1432*4882a593Smuzhiyun 					     sr);
1433*4882a593Smuzhiyun 					lun = 0;
1434*4882a593Smuzhiyun 				}
1435*4882a593Smuzhiyun 			}
1436*4882a593Smuzhiyun 		}
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 		/* Now we look for the command that's reconnecting. */
1439*4882a593Smuzhiyun 
1440*4882a593Smuzhiyun 		cmd = (struct scsi_cmnd *) hostdata->disconnected_Q;
1441*4882a593Smuzhiyun 		patch = NULL;
1442*4882a593Smuzhiyun 		while (cmd) {
1443*4882a593Smuzhiyun 			if (id == cmd->device->id && lun == (u8)cmd->device->lun)
1444*4882a593Smuzhiyun 				break;
1445*4882a593Smuzhiyun 			patch = cmd;
1446*4882a593Smuzhiyun 			cmd = (struct scsi_cmnd *) cmd->host_scribble;
1447*4882a593Smuzhiyun 		}
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 		/* Hmm. Couldn't find a valid command.... What to do? */
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun 		if (!cmd) {
1452*4882a593Smuzhiyun 			printk
1453*4882a593Smuzhiyun 			    ("---TROUBLE: target %d.%d not in disconnect queue---",
1454*4882a593Smuzhiyun 			     id, (u8)lun);
1455*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hostdata->lock, flags);
1456*4882a593Smuzhiyun 			return;
1457*4882a593Smuzhiyun 		}
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 		/* Ok, found the command - now start it up again. */
1460*4882a593Smuzhiyun 
1461*4882a593Smuzhiyun 		if (patch)
1462*4882a593Smuzhiyun 			patch->host_scribble = cmd->host_scribble;
1463*4882a593Smuzhiyun 		else
1464*4882a593Smuzhiyun 			hostdata->disconnected_Q =
1465*4882a593Smuzhiyun 			    (struct scsi_cmnd *) cmd->host_scribble;
1466*4882a593Smuzhiyun 		hostdata->connected = cmd;
1467*4882a593Smuzhiyun 
1468*4882a593Smuzhiyun 		/* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]'
1469*4882a593Smuzhiyun 		 * because these things are preserved over a disconnect.
1470*4882a593Smuzhiyun 		 * But we DO need to fix the DPD bit so it's correct for this command.
1471*4882a593Smuzhiyun 		 */
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun 		if (cmd->sc_data_direction == DMA_TO_DEVICE)
1474*4882a593Smuzhiyun 			write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id);
1475*4882a593Smuzhiyun 		else
1476*4882a593Smuzhiyun 			write_wd33c93(regs, WD_DESTINATION_ID,
1477*4882a593Smuzhiyun 				      cmd->device->id | DSTID_DPD);
1478*4882a593Smuzhiyun 		if (hostdata->level2 >= L2_RESELECT) {
1479*4882a593Smuzhiyun 			write_wd33c93_count(regs, 0);	/* we want a DATA_PHASE interrupt */
1480*4882a593Smuzhiyun 			write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);
1481*4882a593Smuzhiyun 			write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
1482*4882a593Smuzhiyun 			hostdata->state = S_RUNNING_LEVEL2;
1483*4882a593Smuzhiyun 		} else
1484*4882a593Smuzhiyun 			hostdata->state = S_CONNECTED;
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun 		    spin_unlock_irqrestore(&hostdata->lock, flags);
1487*4882a593Smuzhiyun 		break;
1488*4882a593Smuzhiyun 
1489*4882a593Smuzhiyun 	default:
1490*4882a593Smuzhiyun 		printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs);
1491*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hostdata->lock, flags);
1492*4882a593Smuzhiyun 	}
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun 	DB(DB_INTR, printk("} "))
1495*4882a593Smuzhiyun 
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun static void
reset_wd33c93(struct Scsi_Host * instance)1499*4882a593Smuzhiyun reset_wd33c93(struct Scsi_Host *instance)
1500*4882a593Smuzhiyun {
1501*4882a593Smuzhiyun 	struct WD33C93_hostdata *hostdata =
1502*4882a593Smuzhiyun 	    (struct WD33C93_hostdata *) instance->hostdata;
1503*4882a593Smuzhiyun 	const wd33c93_regs regs = hostdata->regs;
1504*4882a593Smuzhiyun 	uchar sr;
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun #ifdef CONFIG_SGI_IP22
1507*4882a593Smuzhiyun 	{
1508*4882a593Smuzhiyun 		int busycount = 0;
1509*4882a593Smuzhiyun 		extern void sgiwd93_reset(unsigned long);
1510*4882a593Smuzhiyun 		/* wait 'til the chip gets some time for us */
1511*4882a593Smuzhiyun 		while ((read_aux_stat(regs) & ASR_BSY) && busycount++ < 100)
1512*4882a593Smuzhiyun 			udelay (10);
1513*4882a593Smuzhiyun 	/*
1514*4882a593Smuzhiyun  	 * there are scsi devices out there, which manage to lock up
1515*4882a593Smuzhiyun 	 * the wd33c93 in a busy condition. In this state it won't
1516*4882a593Smuzhiyun 	 * accept the reset command. The only way to solve this is to
1517*4882a593Smuzhiyun  	 * give the chip a hardware reset (if possible). The code below
1518*4882a593Smuzhiyun 	 * does this for the SGI Indy, where this is possible
1519*4882a593Smuzhiyun 	 */
1520*4882a593Smuzhiyun 	/* still busy ? */
1521*4882a593Smuzhiyun 	if (read_aux_stat(regs) & ASR_BSY)
1522*4882a593Smuzhiyun 		sgiwd93_reset(instance->base); /* yeah, give it the hard one */
1523*4882a593Smuzhiyun 	}
1524*4882a593Smuzhiyun #endif
1525*4882a593Smuzhiyun 
1526*4882a593Smuzhiyun 	write_wd33c93(regs, WD_OWN_ID, OWNID_EAF | OWNID_RAF |
1527*4882a593Smuzhiyun 		      instance->this_id | hostdata->clock_freq);
1528*4882a593Smuzhiyun 	write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
1529*4882a593Smuzhiyun 	write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
1530*4882a593Smuzhiyun 		      calc_sync_xfer(hostdata->default_sx_per / 4,
1531*4882a593Smuzhiyun 				     DEFAULT_SX_OFF, 0, hostdata->sx_table));
1532*4882a593Smuzhiyun 	write_wd33c93(regs, WD_COMMAND, WD_CMD_RESET);
1533*4882a593Smuzhiyun 
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun #ifdef CONFIG_MVME147_SCSI
1536*4882a593Smuzhiyun 	udelay(25);		/* The old wd33c93 on MVME147 needs this, at least */
1537*4882a593Smuzhiyun #endif
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun 	while (!(read_aux_stat(regs) & ASR_INT))
1540*4882a593Smuzhiyun 		;
1541*4882a593Smuzhiyun 	sr = read_wd33c93(regs, WD_SCSI_STATUS);
1542*4882a593Smuzhiyun 
1543*4882a593Smuzhiyun 	hostdata->microcode = read_wd33c93(regs, WD_CDB_1);
1544*4882a593Smuzhiyun 	if (sr == 0x00)
1545*4882a593Smuzhiyun 		hostdata->chip = C_WD33C93;
1546*4882a593Smuzhiyun 	else if (sr == 0x01) {
1547*4882a593Smuzhiyun 		write_wd33c93(regs, WD_QUEUE_TAG, 0xa5);	/* any random number */
1548*4882a593Smuzhiyun 		sr = read_wd33c93(regs, WD_QUEUE_TAG);
1549*4882a593Smuzhiyun 		if (sr == 0xa5) {
1550*4882a593Smuzhiyun 			hostdata->chip = C_WD33C93B;
1551*4882a593Smuzhiyun 			write_wd33c93(regs, WD_QUEUE_TAG, 0);
1552*4882a593Smuzhiyun 		} else
1553*4882a593Smuzhiyun 			hostdata->chip = C_WD33C93A;
1554*4882a593Smuzhiyun 	} else
1555*4882a593Smuzhiyun 		hostdata->chip = C_UNKNOWN_CHIP;
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 	if (hostdata->chip != C_WD33C93B)	/* Fast SCSI unavailable */
1558*4882a593Smuzhiyun 		hostdata->fast = 0;
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun 	write_wd33c93(regs, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
1561*4882a593Smuzhiyun 	write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
1562*4882a593Smuzhiyun }
1563*4882a593Smuzhiyun 
1564*4882a593Smuzhiyun int
wd33c93_host_reset(struct scsi_cmnd * SCpnt)1565*4882a593Smuzhiyun wd33c93_host_reset(struct scsi_cmnd * SCpnt)
1566*4882a593Smuzhiyun {
1567*4882a593Smuzhiyun 	struct Scsi_Host *instance;
1568*4882a593Smuzhiyun 	struct WD33C93_hostdata *hostdata;
1569*4882a593Smuzhiyun 	int i;
1570*4882a593Smuzhiyun 
1571*4882a593Smuzhiyun 	instance = SCpnt->device->host;
1572*4882a593Smuzhiyun 	spin_lock_irq(instance->host_lock);
1573*4882a593Smuzhiyun 	hostdata = (struct WD33C93_hostdata *) instance->hostdata;
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun 	printk("scsi%d: reset. ", instance->host_no);
1576*4882a593Smuzhiyun 	disable_irq(instance->irq);
1577*4882a593Smuzhiyun 
1578*4882a593Smuzhiyun 	hostdata->dma_stop(instance, NULL, 0);
1579*4882a593Smuzhiyun 	for (i = 0; i < 8; i++) {
1580*4882a593Smuzhiyun 		hostdata->busy[i] = 0;
1581*4882a593Smuzhiyun 		hostdata->sync_xfer[i] =
1582*4882a593Smuzhiyun 			calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF,
1583*4882a593Smuzhiyun 					0, hostdata->sx_table);
1584*4882a593Smuzhiyun 		hostdata->sync_stat[i] = SS_UNSET;	/* using default sync values */
1585*4882a593Smuzhiyun 	}
1586*4882a593Smuzhiyun 	hostdata->input_Q = NULL;
1587*4882a593Smuzhiyun 	hostdata->selecting = NULL;
1588*4882a593Smuzhiyun 	hostdata->connected = NULL;
1589*4882a593Smuzhiyun 	hostdata->disconnected_Q = NULL;
1590*4882a593Smuzhiyun 	hostdata->state = S_UNCONNECTED;
1591*4882a593Smuzhiyun 	hostdata->dma = D_DMA_OFF;
1592*4882a593Smuzhiyun 	hostdata->incoming_ptr = 0;
1593*4882a593Smuzhiyun 	hostdata->outgoing_len = 0;
1594*4882a593Smuzhiyun 
1595*4882a593Smuzhiyun 	reset_wd33c93(instance);
1596*4882a593Smuzhiyun 	SCpnt->result = DID_RESET << 16;
1597*4882a593Smuzhiyun 	enable_irq(instance->irq);
1598*4882a593Smuzhiyun 	spin_unlock_irq(instance->host_lock);
1599*4882a593Smuzhiyun 	return SUCCESS;
1600*4882a593Smuzhiyun }
1601*4882a593Smuzhiyun 
1602*4882a593Smuzhiyun int
wd33c93_abort(struct scsi_cmnd * cmd)1603*4882a593Smuzhiyun wd33c93_abort(struct scsi_cmnd * cmd)
1604*4882a593Smuzhiyun {
1605*4882a593Smuzhiyun 	struct Scsi_Host *instance;
1606*4882a593Smuzhiyun 	struct WD33C93_hostdata *hostdata;
1607*4882a593Smuzhiyun 	wd33c93_regs regs;
1608*4882a593Smuzhiyun 	struct scsi_cmnd *tmp, *prev;
1609*4882a593Smuzhiyun 
1610*4882a593Smuzhiyun 	disable_irq(cmd->device->host->irq);
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun 	instance = cmd->device->host;
1613*4882a593Smuzhiyun 	hostdata = (struct WD33C93_hostdata *) instance->hostdata;
1614*4882a593Smuzhiyun 	regs = hostdata->regs;
1615*4882a593Smuzhiyun 
1616*4882a593Smuzhiyun /*
1617*4882a593Smuzhiyun  * Case 1 : If the command hasn't been issued yet, we simply remove it
1618*4882a593Smuzhiyun  *     from the input_Q.
1619*4882a593Smuzhiyun  */
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun 	tmp = (struct scsi_cmnd *) hostdata->input_Q;
1622*4882a593Smuzhiyun 	prev = NULL;
1623*4882a593Smuzhiyun 	while (tmp) {
1624*4882a593Smuzhiyun 		if (tmp == cmd) {
1625*4882a593Smuzhiyun 			if (prev)
1626*4882a593Smuzhiyun 				prev->host_scribble = cmd->host_scribble;
1627*4882a593Smuzhiyun 			else
1628*4882a593Smuzhiyun 				hostdata->input_Q =
1629*4882a593Smuzhiyun 				    (struct scsi_cmnd *) cmd->host_scribble;
1630*4882a593Smuzhiyun 			cmd->host_scribble = NULL;
1631*4882a593Smuzhiyun 			cmd->result = DID_ABORT << 16;
1632*4882a593Smuzhiyun 			printk
1633*4882a593Smuzhiyun 			    ("scsi%d: Abort - removing command from input_Q. ",
1634*4882a593Smuzhiyun 			     instance->host_no);
1635*4882a593Smuzhiyun 			enable_irq(cmd->device->host->irq);
1636*4882a593Smuzhiyun 			cmd->scsi_done(cmd);
1637*4882a593Smuzhiyun 			return SUCCESS;
1638*4882a593Smuzhiyun 		}
1639*4882a593Smuzhiyun 		prev = tmp;
1640*4882a593Smuzhiyun 		tmp = (struct scsi_cmnd *) tmp->host_scribble;
1641*4882a593Smuzhiyun 	}
1642*4882a593Smuzhiyun 
1643*4882a593Smuzhiyun /*
1644*4882a593Smuzhiyun  * Case 2 : If the command is connected, we're going to fail the abort
1645*4882a593Smuzhiyun  *     and let the high level SCSI driver retry at a later time or
1646*4882a593Smuzhiyun  *     issue a reset.
1647*4882a593Smuzhiyun  *
1648*4882a593Smuzhiyun  *     Timeouts, and therefore aborted commands, will be highly unlikely
1649*4882a593Smuzhiyun  *     and handling them cleanly in this situation would make the common
1650*4882a593Smuzhiyun  *     case of noresets less efficient, and would pollute our code.  So,
1651*4882a593Smuzhiyun  *     we fail.
1652*4882a593Smuzhiyun  */
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	if (hostdata->connected == cmd) {
1655*4882a593Smuzhiyun 		uchar sr, asr;
1656*4882a593Smuzhiyun 		unsigned long timeout;
1657*4882a593Smuzhiyun 
1658*4882a593Smuzhiyun 		printk("scsi%d: Aborting connected command - ",
1659*4882a593Smuzhiyun 		       instance->host_no);
1660*4882a593Smuzhiyun 
1661*4882a593Smuzhiyun 		printk("stopping DMA - ");
1662*4882a593Smuzhiyun 		if (hostdata->dma == D_DMA_RUNNING) {
1663*4882a593Smuzhiyun 			hostdata->dma_stop(instance, cmd, 0);
1664*4882a593Smuzhiyun 			hostdata->dma = D_DMA_OFF;
1665*4882a593Smuzhiyun 		}
1666*4882a593Smuzhiyun 
1667*4882a593Smuzhiyun 		printk("sending wd33c93 ABORT command - ");
1668*4882a593Smuzhiyun 		write_wd33c93(regs, WD_CONTROL,
1669*4882a593Smuzhiyun 			      CTRL_IDI | CTRL_EDI | CTRL_POLLED);
1670*4882a593Smuzhiyun 		write_wd33c93_cmd(regs, WD_CMD_ABORT);
1671*4882a593Smuzhiyun 
1672*4882a593Smuzhiyun /* Now we have to attempt to flush out the FIFO... */
1673*4882a593Smuzhiyun 
1674*4882a593Smuzhiyun 		printk("flushing fifo - ");
1675*4882a593Smuzhiyun 		timeout = 1000000;
1676*4882a593Smuzhiyun 		do {
1677*4882a593Smuzhiyun 			asr = read_aux_stat(regs);
1678*4882a593Smuzhiyun 			if (asr & ASR_DBR)
1679*4882a593Smuzhiyun 				read_wd33c93(regs, WD_DATA);
1680*4882a593Smuzhiyun 		} while (!(asr & ASR_INT) && timeout-- > 0);
1681*4882a593Smuzhiyun 		sr = read_wd33c93(regs, WD_SCSI_STATUS);
1682*4882a593Smuzhiyun 		printk
1683*4882a593Smuzhiyun 		    ("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ",
1684*4882a593Smuzhiyun 		     asr, sr, read_wd33c93_count(regs), timeout);
1685*4882a593Smuzhiyun 
1686*4882a593Smuzhiyun 		/*
1687*4882a593Smuzhiyun 		 * Abort command processed.
1688*4882a593Smuzhiyun 		 * Still connected.
1689*4882a593Smuzhiyun 		 * We must disconnect.
1690*4882a593Smuzhiyun 		 */
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun 		printk("sending wd33c93 DISCONNECT command - ");
1693*4882a593Smuzhiyun 		write_wd33c93_cmd(regs, WD_CMD_DISCONNECT);
1694*4882a593Smuzhiyun 
1695*4882a593Smuzhiyun 		timeout = 1000000;
1696*4882a593Smuzhiyun 		asr = read_aux_stat(regs);
1697*4882a593Smuzhiyun 		while ((asr & ASR_CIP) && timeout-- > 0)
1698*4882a593Smuzhiyun 			asr = read_aux_stat(regs);
1699*4882a593Smuzhiyun 		sr = read_wd33c93(regs, WD_SCSI_STATUS);
1700*4882a593Smuzhiyun 		printk("asr=%02x, sr=%02x.", asr, sr);
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun 		hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xff));
1703*4882a593Smuzhiyun 		hostdata->connected = NULL;
1704*4882a593Smuzhiyun 		hostdata->state = S_UNCONNECTED;
1705*4882a593Smuzhiyun 		cmd->result = DID_ABORT << 16;
1706*4882a593Smuzhiyun 
1707*4882a593Smuzhiyun /*      sti();*/
1708*4882a593Smuzhiyun 		wd33c93_execute(instance);
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun 		enable_irq(cmd->device->host->irq);
1711*4882a593Smuzhiyun 		cmd->scsi_done(cmd);
1712*4882a593Smuzhiyun 		return SUCCESS;
1713*4882a593Smuzhiyun 	}
1714*4882a593Smuzhiyun 
1715*4882a593Smuzhiyun /*
1716*4882a593Smuzhiyun  * Case 3: If the command is currently disconnected from the bus,
1717*4882a593Smuzhiyun  * we're not going to expend much effort here: Let's just return
1718*4882a593Smuzhiyun  * an ABORT_SNOOZE and hope for the best...
1719*4882a593Smuzhiyun  */
1720*4882a593Smuzhiyun 
1721*4882a593Smuzhiyun 	tmp = (struct scsi_cmnd *) hostdata->disconnected_Q;
1722*4882a593Smuzhiyun 	while (tmp) {
1723*4882a593Smuzhiyun 		if (tmp == cmd) {
1724*4882a593Smuzhiyun 			printk
1725*4882a593Smuzhiyun 			    ("scsi%d: Abort - command found on disconnected_Q - ",
1726*4882a593Smuzhiyun 			     instance->host_no);
1727*4882a593Smuzhiyun 			printk("Abort SNOOZE. ");
1728*4882a593Smuzhiyun 			enable_irq(cmd->device->host->irq);
1729*4882a593Smuzhiyun 			return FAILED;
1730*4882a593Smuzhiyun 		}
1731*4882a593Smuzhiyun 		tmp = (struct scsi_cmnd *) tmp->host_scribble;
1732*4882a593Smuzhiyun 	}
1733*4882a593Smuzhiyun 
1734*4882a593Smuzhiyun /*
1735*4882a593Smuzhiyun  * Case 4 : If we reached this point, the command was not found in any of
1736*4882a593Smuzhiyun  *     the queues.
1737*4882a593Smuzhiyun  *
1738*4882a593Smuzhiyun  * We probably reached this point because of an unlikely race condition
1739*4882a593Smuzhiyun  * between the command completing successfully and the abortion code,
1740*4882a593Smuzhiyun  * so we won't panic, but we will notify the user in case something really
1741*4882a593Smuzhiyun  * broke.
1742*4882a593Smuzhiyun  */
1743*4882a593Smuzhiyun 
1744*4882a593Smuzhiyun /*   sti();*/
1745*4882a593Smuzhiyun 	wd33c93_execute(instance);
1746*4882a593Smuzhiyun 
1747*4882a593Smuzhiyun 	enable_irq(cmd->device->host->irq);
1748*4882a593Smuzhiyun 	printk("scsi%d: warning : SCSI command probably completed successfully"
1749*4882a593Smuzhiyun 	       "         before abortion. ", instance->host_no);
1750*4882a593Smuzhiyun 	return FAILED;
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun 
1753*4882a593Smuzhiyun #define MAX_WD33C93_HOSTS 4
1754*4882a593Smuzhiyun #define MAX_SETUP_ARGS ARRAY_SIZE(setup_args)
1755*4882a593Smuzhiyun #define SETUP_BUFFER_SIZE 200
1756*4882a593Smuzhiyun static char setup_buffer[SETUP_BUFFER_SIZE];
1757*4882a593Smuzhiyun static char setup_used[MAX_SETUP_ARGS];
1758*4882a593Smuzhiyun static int done_setup = 0;
1759*4882a593Smuzhiyun 
1760*4882a593Smuzhiyun static int
wd33c93_setup(char * str)1761*4882a593Smuzhiyun wd33c93_setup(char *str)
1762*4882a593Smuzhiyun {
1763*4882a593Smuzhiyun 	int i;
1764*4882a593Smuzhiyun 	char *p1, *p2;
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun 	/* The kernel does some processing of the command-line before calling
1767*4882a593Smuzhiyun 	 * this function: If it begins with any decimal or hex number arguments,
1768*4882a593Smuzhiyun 	 * ints[0] = how many numbers found and ints[1] through [n] are the values
1769*4882a593Smuzhiyun 	 * themselves. str points to where the non-numeric arguments (if any)
1770*4882a593Smuzhiyun 	 * start: We do our own parsing of those. We construct synthetic 'nosync'
1771*4882a593Smuzhiyun 	 * keywords out of numeric args (to maintain compatibility with older
1772*4882a593Smuzhiyun 	 * versions) and then add the rest of the arguments.
1773*4882a593Smuzhiyun 	 */
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun 	p1 = setup_buffer;
1776*4882a593Smuzhiyun 	*p1 = '\0';
1777*4882a593Smuzhiyun 	if (str)
1778*4882a593Smuzhiyun 		strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
1779*4882a593Smuzhiyun 	setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
1780*4882a593Smuzhiyun 	p1 = setup_buffer;
1781*4882a593Smuzhiyun 	i = 0;
1782*4882a593Smuzhiyun 	while (*p1 && (i < MAX_SETUP_ARGS)) {
1783*4882a593Smuzhiyun 		p2 = strchr(p1, ',');
1784*4882a593Smuzhiyun 		if (p2) {
1785*4882a593Smuzhiyun 			*p2 = '\0';
1786*4882a593Smuzhiyun 			if (p1 != p2)
1787*4882a593Smuzhiyun 				setup_args[i] = p1;
1788*4882a593Smuzhiyun 			p1 = p2 + 1;
1789*4882a593Smuzhiyun 			i++;
1790*4882a593Smuzhiyun 		} else {
1791*4882a593Smuzhiyun 			setup_args[i] = p1;
1792*4882a593Smuzhiyun 			break;
1793*4882a593Smuzhiyun 		}
1794*4882a593Smuzhiyun 	}
1795*4882a593Smuzhiyun 	for (i = 0; i < MAX_SETUP_ARGS; i++)
1796*4882a593Smuzhiyun 		setup_used[i] = 0;
1797*4882a593Smuzhiyun 	done_setup = 1;
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun 	return 1;
1800*4882a593Smuzhiyun }
1801*4882a593Smuzhiyun __setup("wd33c93=", wd33c93_setup);
1802*4882a593Smuzhiyun 
1803*4882a593Smuzhiyun /* check_setup_args() returns index if key found, 0 if not
1804*4882a593Smuzhiyun  */
1805*4882a593Smuzhiyun static int
check_setup_args(char * key,int * flags,int * val,char * buf)1806*4882a593Smuzhiyun check_setup_args(char *key, int *flags, int *val, char *buf)
1807*4882a593Smuzhiyun {
1808*4882a593Smuzhiyun 	int x;
1809*4882a593Smuzhiyun 	char *cp;
1810*4882a593Smuzhiyun 
1811*4882a593Smuzhiyun 	for (x = 0; x < MAX_SETUP_ARGS; x++) {
1812*4882a593Smuzhiyun 		if (setup_used[x])
1813*4882a593Smuzhiyun 			continue;
1814*4882a593Smuzhiyun 		if (!strncmp(setup_args[x], key, strlen(key)))
1815*4882a593Smuzhiyun 			break;
1816*4882a593Smuzhiyun 		if (!strncmp(setup_args[x], "next", strlen("next")))
1817*4882a593Smuzhiyun 			return 0;
1818*4882a593Smuzhiyun 	}
1819*4882a593Smuzhiyun 	if (x == MAX_SETUP_ARGS)
1820*4882a593Smuzhiyun 		return 0;
1821*4882a593Smuzhiyun 	setup_used[x] = 1;
1822*4882a593Smuzhiyun 	cp = setup_args[x] + strlen(key);
1823*4882a593Smuzhiyun 	*val = -1;
1824*4882a593Smuzhiyun 	if (*cp != ':')
1825*4882a593Smuzhiyun 		return ++x;
1826*4882a593Smuzhiyun 	cp++;
1827*4882a593Smuzhiyun 	if ((*cp >= '0') && (*cp <= '9')) {
1828*4882a593Smuzhiyun 		*val = simple_strtoul(cp, NULL, 0);
1829*4882a593Smuzhiyun 	}
1830*4882a593Smuzhiyun 	return ++x;
1831*4882a593Smuzhiyun }
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun /*
1834*4882a593Smuzhiyun  * Calculate internal data-transfer-clock cycle from input-clock
1835*4882a593Smuzhiyun  * frequency (/MHz) and fill 'sx_table'.
1836*4882a593Smuzhiyun  *
1837*4882a593Smuzhiyun  * The original driver used to rely on a fixed sx_table, containing periods
1838*4882a593Smuzhiyun  * for (only) the lower limits of the respective input-clock-frequency ranges
1839*4882a593Smuzhiyun  * (8-10/12-15/16-20 MHz). Although it seems, that no problems occurred with
1840*4882a593Smuzhiyun  * this setting so far, it might be desirable to adjust the transfer periods
1841*4882a593Smuzhiyun  * closer to the really attached, possibly 25% higher, input-clock, since
1842*4882a593Smuzhiyun  * - the wd33c93 may really use a significant shorter period, than it has
1843*4882a593Smuzhiyun  *   negotiated (eg. thrashing the target, which expects 4/8MHz, with 5/10MHz
1844*4882a593Smuzhiyun  *   instead).
1845*4882a593Smuzhiyun  * - the wd33c93 may ask the target for a lower transfer rate, than the target
1846*4882a593Smuzhiyun  *   is capable of (eg. negotiating for an assumed minimum of 252ns instead of
1847*4882a593Smuzhiyun  *   possible 200ns, which indeed shows up in tests as an approx. 10% lower
1848*4882a593Smuzhiyun  *   transfer rate).
1849*4882a593Smuzhiyun  */
1850*4882a593Smuzhiyun static inline unsigned int
round_4(unsigned int x)1851*4882a593Smuzhiyun round_4(unsigned int x)
1852*4882a593Smuzhiyun {
1853*4882a593Smuzhiyun 	switch (x & 3) {
1854*4882a593Smuzhiyun 		case 1: --x;
1855*4882a593Smuzhiyun 			break;
1856*4882a593Smuzhiyun 		case 2: ++x;
1857*4882a593Smuzhiyun 			fallthrough;
1858*4882a593Smuzhiyun 		case 3: ++x;
1859*4882a593Smuzhiyun 	}
1860*4882a593Smuzhiyun 	return x;
1861*4882a593Smuzhiyun }
1862*4882a593Smuzhiyun 
1863*4882a593Smuzhiyun static void
calc_sx_table(unsigned int mhz,struct sx_period sx_table[9])1864*4882a593Smuzhiyun calc_sx_table(unsigned int mhz, struct sx_period sx_table[9])
1865*4882a593Smuzhiyun {
1866*4882a593Smuzhiyun 	unsigned int d, i;
1867*4882a593Smuzhiyun 	if (mhz < 11)
1868*4882a593Smuzhiyun 		d = 2;	/* divisor for  8-10 MHz input-clock */
1869*4882a593Smuzhiyun 	else if (mhz < 16)
1870*4882a593Smuzhiyun 		d = 3;	/* divisor for 12-15 MHz input-clock */
1871*4882a593Smuzhiyun 	else
1872*4882a593Smuzhiyun 		d = 4;	/* divisor for 16-20 MHz input-clock */
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun 	d = (100000 * d) / 2 / mhz; /* 100 x DTCC / nanosec */
1875*4882a593Smuzhiyun 
1876*4882a593Smuzhiyun 	sx_table[0].period_ns = 1;
1877*4882a593Smuzhiyun 	sx_table[0].reg_value = 0x20;
1878*4882a593Smuzhiyun 	for (i = 1; i < 8; i++) {
1879*4882a593Smuzhiyun 		sx_table[i].period_ns = round_4((i+1)*d / 100);
1880*4882a593Smuzhiyun 		sx_table[i].reg_value = (i+1)*0x10;
1881*4882a593Smuzhiyun 	}
1882*4882a593Smuzhiyun 	sx_table[7].reg_value = 0;
1883*4882a593Smuzhiyun 	sx_table[8].period_ns = 0;
1884*4882a593Smuzhiyun 	sx_table[8].reg_value = 0;
1885*4882a593Smuzhiyun }
1886*4882a593Smuzhiyun 
1887*4882a593Smuzhiyun /*
1888*4882a593Smuzhiyun  * check and, maybe, map an init- or "clock:"- argument.
1889*4882a593Smuzhiyun  */
1890*4882a593Smuzhiyun static uchar
set_clk_freq(int freq,int * mhz)1891*4882a593Smuzhiyun set_clk_freq(int freq, int *mhz)
1892*4882a593Smuzhiyun {
1893*4882a593Smuzhiyun 	int x = freq;
1894*4882a593Smuzhiyun 	if (WD33C93_FS_8_10 == freq)
1895*4882a593Smuzhiyun 		freq = 8;
1896*4882a593Smuzhiyun 	else if (WD33C93_FS_12_15 == freq)
1897*4882a593Smuzhiyun 		freq = 12;
1898*4882a593Smuzhiyun 	else if (WD33C93_FS_16_20 == freq)
1899*4882a593Smuzhiyun 		freq = 16;
1900*4882a593Smuzhiyun 	else if (freq > 7 && freq < 11)
1901*4882a593Smuzhiyun 		x = WD33C93_FS_8_10;
1902*4882a593Smuzhiyun 		else if (freq > 11 && freq < 16)
1903*4882a593Smuzhiyun 		x = WD33C93_FS_12_15;
1904*4882a593Smuzhiyun 		else if (freq > 15 && freq < 21)
1905*4882a593Smuzhiyun 		x = WD33C93_FS_16_20;
1906*4882a593Smuzhiyun 	else {
1907*4882a593Smuzhiyun 			/* Hmm, wouldn't it be safer to assume highest freq here? */
1908*4882a593Smuzhiyun 		x = WD33C93_FS_8_10;
1909*4882a593Smuzhiyun 		freq = 8;
1910*4882a593Smuzhiyun 	}
1911*4882a593Smuzhiyun 	*mhz = freq;
1912*4882a593Smuzhiyun 	return x;
1913*4882a593Smuzhiyun }
1914*4882a593Smuzhiyun 
1915*4882a593Smuzhiyun /*
1916*4882a593Smuzhiyun  * to be used with the resync: fast: ... options
1917*4882a593Smuzhiyun  */
set_resync(struct WD33C93_hostdata * hd,int mask)1918*4882a593Smuzhiyun static inline void set_resync ( struct WD33C93_hostdata *hd, int mask )
1919*4882a593Smuzhiyun {
1920*4882a593Smuzhiyun 	int i;
1921*4882a593Smuzhiyun 	for (i = 0; i < 8; i++)
1922*4882a593Smuzhiyun 		if (mask & (1 << i))
1923*4882a593Smuzhiyun 			hd->sync_stat[i] = SS_UNSET;
1924*4882a593Smuzhiyun }
1925*4882a593Smuzhiyun 
1926*4882a593Smuzhiyun void
wd33c93_init(struct Scsi_Host * instance,const wd33c93_regs regs,dma_setup_t setup,dma_stop_t stop,int clock_freq)1927*4882a593Smuzhiyun wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
1928*4882a593Smuzhiyun 	     dma_setup_t setup, dma_stop_t stop, int clock_freq)
1929*4882a593Smuzhiyun {
1930*4882a593Smuzhiyun 	struct WD33C93_hostdata *hostdata;
1931*4882a593Smuzhiyun 	int i;
1932*4882a593Smuzhiyun 	int flags;
1933*4882a593Smuzhiyun 	int val;
1934*4882a593Smuzhiyun 	char buf[32];
1935*4882a593Smuzhiyun 
1936*4882a593Smuzhiyun 	if (!done_setup && setup_strings)
1937*4882a593Smuzhiyun 		wd33c93_setup(setup_strings);
1938*4882a593Smuzhiyun 
1939*4882a593Smuzhiyun 	hostdata = (struct WD33C93_hostdata *) instance->hostdata;
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun 	hostdata->regs = regs;
1942*4882a593Smuzhiyun 	hostdata->clock_freq = set_clk_freq(clock_freq, &i);
1943*4882a593Smuzhiyun 	calc_sx_table(i, hostdata->sx_table);
1944*4882a593Smuzhiyun 	hostdata->dma_setup = setup;
1945*4882a593Smuzhiyun 	hostdata->dma_stop = stop;
1946*4882a593Smuzhiyun 	hostdata->dma_bounce_buffer = NULL;
1947*4882a593Smuzhiyun 	hostdata->dma_bounce_len = 0;
1948*4882a593Smuzhiyun 	for (i = 0; i < 8; i++) {
1949*4882a593Smuzhiyun 		hostdata->busy[i] = 0;
1950*4882a593Smuzhiyun 		hostdata->sync_xfer[i] =
1951*4882a593Smuzhiyun 			calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF,
1952*4882a593Smuzhiyun 					0, hostdata->sx_table);
1953*4882a593Smuzhiyun 		hostdata->sync_stat[i] = SS_UNSET;	/* using default sync values */
1954*4882a593Smuzhiyun #ifdef PROC_STATISTICS
1955*4882a593Smuzhiyun 		hostdata->cmd_cnt[i] = 0;
1956*4882a593Smuzhiyun 		hostdata->disc_allowed_cnt[i] = 0;
1957*4882a593Smuzhiyun 		hostdata->disc_done_cnt[i] = 0;
1958*4882a593Smuzhiyun #endif
1959*4882a593Smuzhiyun 	}
1960*4882a593Smuzhiyun 	hostdata->input_Q = NULL;
1961*4882a593Smuzhiyun 	hostdata->selecting = NULL;
1962*4882a593Smuzhiyun 	hostdata->connected = NULL;
1963*4882a593Smuzhiyun 	hostdata->disconnected_Q = NULL;
1964*4882a593Smuzhiyun 	hostdata->state = S_UNCONNECTED;
1965*4882a593Smuzhiyun 	hostdata->dma = D_DMA_OFF;
1966*4882a593Smuzhiyun 	hostdata->level2 = L2_BASIC;
1967*4882a593Smuzhiyun 	hostdata->disconnect = DIS_ADAPTIVE;
1968*4882a593Smuzhiyun 	hostdata->args = DEBUG_DEFAULTS;
1969*4882a593Smuzhiyun 	hostdata->incoming_ptr = 0;
1970*4882a593Smuzhiyun 	hostdata->outgoing_len = 0;
1971*4882a593Smuzhiyun 	hostdata->default_sx_per = DEFAULT_SX_PER;
1972*4882a593Smuzhiyun 	hostdata->no_dma = 0;	/* default is DMA enabled */
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun #ifdef PROC_INTERFACE
1975*4882a593Smuzhiyun 	hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS |
1976*4882a593Smuzhiyun 	    PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP;
1977*4882a593Smuzhiyun #ifdef PROC_STATISTICS
1978*4882a593Smuzhiyun 	hostdata->dma_cnt = 0;
1979*4882a593Smuzhiyun 	hostdata->pio_cnt = 0;
1980*4882a593Smuzhiyun 	hostdata->int_cnt = 0;
1981*4882a593Smuzhiyun #endif
1982*4882a593Smuzhiyun #endif
1983*4882a593Smuzhiyun 
1984*4882a593Smuzhiyun 	if (check_setup_args("clock", &flags, &val, buf)) {
1985*4882a593Smuzhiyun 		hostdata->clock_freq = set_clk_freq(val, &val);
1986*4882a593Smuzhiyun 		calc_sx_table(val, hostdata->sx_table);
1987*4882a593Smuzhiyun 	}
1988*4882a593Smuzhiyun 
1989*4882a593Smuzhiyun 	if (check_setup_args("nosync", &flags, &val, buf))
1990*4882a593Smuzhiyun 		hostdata->no_sync = val;
1991*4882a593Smuzhiyun 
1992*4882a593Smuzhiyun 	if (check_setup_args("nodma", &flags, &val, buf))
1993*4882a593Smuzhiyun 		hostdata->no_dma = (val == -1) ? 1 : val;
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun 	if (check_setup_args("period", &flags, &val, buf))
1996*4882a593Smuzhiyun 		hostdata->default_sx_per =
1997*4882a593Smuzhiyun 		    hostdata->sx_table[round_period((unsigned int) val,
1998*4882a593Smuzhiyun 		                                    hostdata->sx_table)].period_ns;
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun 	if (check_setup_args("disconnect", &flags, &val, buf)) {
2001*4882a593Smuzhiyun 		if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
2002*4882a593Smuzhiyun 			hostdata->disconnect = val;
2003*4882a593Smuzhiyun 		else
2004*4882a593Smuzhiyun 			hostdata->disconnect = DIS_ADAPTIVE;
2005*4882a593Smuzhiyun 	}
2006*4882a593Smuzhiyun 
2007*4882a593Smuzhiyun 	if (check_setup_args("level2", &flags, &val, buf))
2008*4882a593Smuzhiyun 		hostdata->level2 = val;
2009*4882a593Smuzhiyun 
2010*4882a593Smuzhiyun 	if (check_setup_args("debug", &flags, &val, buf))
2011*4882a593Smuzhiyun 		hostdata->args = val & DB_MASK;
2012*4882a593Smuzhiyun 
2013*4882a593Smuzhiyun 	if (check_setup_args("burst", &flags, &val, buf))
2014*4882a593Smuzhiyun 		hostdata->dma_mode = val ? CTRL_BURST:CTRL_DMA;
2015*4882a593Smuzhiyun 
2016*4882a593Smuzhiyun 	if (WD33C93_FS_16_20 == hostdata->clock_freq /* divisor 4 */
2017*4882a593Smuzhiyun 		&& check_setup_args("fast", &flags, &val, buf))
2018*4882a593Smuzhiyun 		hostdata->fast = !!val;
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun 	if ((i = check_setup_args("next", &flags, &val, buf))) {
2021*4882a593Smuzhiyun 		while (i)
2022*4882a593Smuzhiyun 			setup_used[--i] = 1;
2023*4882a593Smuzhiyun 	}
2024*4882a593Smuzhiyun #ifdef PROC_INTERFACE
2025*4882a593Smuzhiyun 	if (check_setup_args("proc", &flags, &val, buf))
2026*4882a593Smuzhiyun 		hostdata->proc = val;
2027*4882a593Smuzhiyun #endif
2028*4882a593Smuzhiyun 
2029*4882a593Smuzhiyun 	spin_lock_irq(&hostdata->lock);
2030*4882a593Smuzhiyun 	reset_wd33c93(instance);
2031*4882a593Smuzhiyun 	spin_unlock_irq(&hostdata->lock);
2032*4882a593Smuzhiyun 
2033*4882a593Smuzhiyun 	printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",
2034*4882a593Smuzhiyun 	       instance->host_no,
2035*4882a593Smuzhiyun 	       (hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip ==
2036*4882a593Smuzhiyun 							    C_WD33C93A) ?
2037*4882a593Smuzhiyun 	       "WD33c93A" : (hostdata->chip ==
2038*4882a593Smuzhiyun 			     C_WD33C93B) ? "WD33c93B" : "unknown",
2039*4882a593Smuzhiyun 	       hostdata->microcode, hostdata->no_sync, hostdata->no_dma);
2040*4882a593Smuzhiyun #ifdef DEBUGGING_ON
2041*4882a593Smuzhiyun 	printk(" debug_flags=0x%02x\n", hostdata->args);
2042*4882a593Smuzhiyun #else
2043*4882a593Smuzhiyun 	printk(" debugging=OFF\n");
2044*4882a593Smuzhiyun #endif
2045*4882a593Smuzhiyun 	printk("           setup_args=");
2046*4882a593Smuzhiyun 	for (i = 0; i < MAX_SETUP_ARGS; i++)
2047*4882a593Smuzhiyun 		printk("%s,", setup_args[i]);
2048*4882a593Smuzhiyun 	printk("\n");
2049*4882a593Smuzhiyun 	printk("           Version %s - %s\n", WD33C93_VERSION, WD33C93_DATE);
2050*4882a593Smuzhiyun }
2051*4882a593Smuzhiyun 
wd33c93_write_info(struct Scsi_Host * instance,char * buf,int len)2052*4882a593Smuzhiyun int wd33c93_write_info(struct Scsi_Host *instance, char *buf, int len)
2053*4882a593Smuzhiyun {
2054*4882a593Smuzhiyun #ifdef PROC_INTERFACE
2055*4882a593Smuzhiyun 	char *bp;
2056*4882a593Smuzhiyun 	struct WD33C93_hostdata *hd;
2057*4882a593Smuzhiyun 	int x;
2058*4882a593Smuzhiyun 
2059*4882a593Smuzhiyun 	hd = (struct WD33C93_hostdata *) instance->hostdata;
2060*4882a593Smuzhiyun 
2061*4882a593Smuzhiyun /* We accept the following
2062*4882a593Smuzhiyun  * keywords (same format as command-line, but arguments are not optional):
2063*4882a593Smuzhiyun  *    debug
2064*4882a593Smuzhiyun  *    disconnect
2065*4882a593Smuzhiyun  *    period
2066*4882a593Smuzhiyun  *    resync
2067*4882a593Smuzhiyun  *    proc
2068*4882a593Smuzhiyun  *    nodma
2069*4882a593Smuzhiyun  *    level2
2070*4882a593Smuzhiyun  *    burst
2071*4882a593Smuzhiyun  *    fast
2072*4882a593Smuzhiyun  *    nosync
2073*4882a593Smuzhiyun  */
2074*4882a593Smuzhiyun 
2075*4882a593Smuzhiyun 	buf[len] = '\0';
2076*4882a593Smuzhiyun 	for (bp = buf; *bp; ) {
2077*4882a593Smuzhiyun 		while (',' == *bp || ' ' == *bp)
2078*4882a593Smuzhiyun 			++bp;
2079*4882a593Smuzhiyun 	if (!strncmp(bp, "debug:", 6)) {
2080*4882a593Smuzhiyun 			hd->args = simple_strtoul(bp+6, &bp, 0) & DB_MASK;
2081*4882a593Smuzhiyun 	} else if (!strncmp(bp, "disconnect:", 11)) {
2082*4882a593Smuzhiyun 			x = simple_strtoul(bp+11, &bp, 0);
2083*4882a593Smuzhiyun 		if (x < DIS_NEVER || x > DIS_ALWAYS)
2084*4882a593Smuzhiyun 			x = DIS_ADAPTIVE;
2085*4882a593Smuzhiyun 		hd->disconnect = x;
2086*4882a593Smuzhiyun 	} else if (!strncmp(bp, "period:", 7)) {
2087*4882a593Smuzhiyun 		x = simple_strtoul(bp+7, &bp, 0);
2088*4882a593Smuzhiyun 		hd->default_sx_per =
2089*4882a593Smuzhiyun 			hd->sx_table[round_period((unsigned int) x,
2090*4882a593Smuzhiyun 						  hd->sx_table)].period_ns;
2091*4882a593Smuzhiyun 	} else if (!strncmp(bp, "resync:", 7)) {
2092*4882a593Smuzhiyun 			set_resync(hd, (int)simple_strtoul(bp+7, &bp, 0));
2093*4882a593Smuzhiyun 	} else if (!strncmp(bp, "proc:", 5)) {
2094*4882a593Smuzhiyun 			hd->proc = simple_strtoul(bp+5, &bp, 0);
2095*4882a593Smuzhiyun 	} else if (!strncmp(bp, "nodma:", 6)) {
2096*4882a593Smuzhiyun 			hd->no_dma = simple_strtoul(bp+6, &bp, 0);
2097*4882a593Smuzhiyun 	} else if (!strncmp(bp, "level2:", 7)) {
2098*4882a593Smuzhiyun 			hd->level2 = simple_strtoul(bp+7, &bp, 0);
2099*4882a593Smuzhiyun 		} else if (!strncmp(bp, "burst:", 6)) {
2100*4882a593Smuzhiyun 			hd->dma_mode =
2101*4882a593Smuzhiyun 				simple_strtol(bp+6, &bp, 0) ? CTRL_BURST:CTRL_DMA;
2102*4882a593Smuzhiyun 		} else if (!strncmp(bp, "fast:", 5)) {
2103*4882a593Smuzhiyun 			x = !!simple_strtol(bp+5, &bp, 0);
2104*4882a593Smuzhiyun 			if (x != hd->fast)
2105*4882a593Smuzhiyun 				set_resync(hd, 0xff);
2106*4882a593Smuzhiyun 			hd->fast = x;
2107*4882a593Smuzhiyun 		} else if (!strncmp(bp, "nosync:", 7)) {
2108*4882a593Smuzhiyun 			x = simple_strtoul(bp+7, &bp, 0);
2109*4882a593Smuzhiyun 			set_resync(hd, x ^ hd->no_sync);
2110*4882a593Smuzhiyun 			hd->no_sync = x;
2111*4882a593Smuzhiyun 		} else {
2112*4882a593Smuzhiyun 			break; /* unknown keyword,syntax-error,... */
2113*4882a593Smuzhiyun 		}
2114*4882a593Smuzhiyun 	}
2115*4882a593Smuzhiyun 	return len;
2116*4882a593Smuzhiyun #else
2117*4882a593Smuzhiyun 	return 0;
2118*4882a593Smuzhiyun #endif
2119*4882a593Smuzhiyun }
2120*4882a593Smuzhiyun 
2121*4882a593Smuzhiyun int
wd33c93_show_info(struct seq_file * m,struct Scsi_Host * instance)2122*4882a593Smuzhiyun wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance)
2123*4882a593Smuzhiyun {
2124*4882a593Smuzhiyun #ifdef PROC_INTERFACE
2125*4882a593Smuzhiyun 	struct WD33C93_hostdata *hd;
2126*4882a593Smuzhiyun 	struct scsi_cmnd *cmd;
2127*4882a593Smuzhiyun 	int x;
2128*4882a593Smuzhiyun 
2129*4882a593Smuzhiyun 	hd = (struct WD33C93_hostdata *) instance->hostdata;
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 	spin_lock_irq(&hd->lock);
2132*4882a593Smuzhiyun 	if (hd->proc & PR_VERSION)
2133*4882a593Smuzhiyun 		seq_printf(m, "\nVersion %s - %s.",
2134*4882a593Smuzhiyun 			WD33C93_VERSION, WD33C93_DATE);
2135*4882a593Smuzhiyun 
2136*4882a593Smuzhiyun 	if (hd->proc & PR_INFO) {
2137*4882a593Smuzhiyun 		seq_printf(m, "\nclock_freq=%02x no_sync=%02x no_dma=%d"
2138*4882a593Smuzhiyun 			" dma_mode=%02x fast=%d",
2139*4882a593Smuzhiyun 			hd->clock_freq, hd->no_sync, hd->no_dma, hd->dma_mode, hd->fast);
2140*4882a593Smuzhiyun 		seq_puts(m, "\nsync_xfer[] =       ");
2141*4882a593Smuzhiyun 		for (x = 0; x < 7; x++)
2142*4882a593Smuzhiyun 			seq_printf(m, "\t%02x", hd->sync_xfer[x]);
2143*4882a593Smuzhiyun 		seq_puts(m, "\nsync_stat[] =       ");
2144*4882a593Smuzhiyun 		for (x = 0; x < 7; x++)
2145*4882a593Smuzhiyun 			seq_printf(m, "\t%02x", hd->sync_stat[x]);
2146*4882a593Smuzhiyun 	}
2147*4882a593Smuzhiyun #ifdef PROC_STATISTICS
2148*4882a593Smuzhiyun 	if (hd->proc & PR_STATISTICS) {
2149*4882a593Smuzhiyun 		seq_puts(m, "\ncommands issued:    ");
2150*4882a593Smuzhiyun 		for (x = 0; x < 7; x++)
2151*4882a593Smuzhiyun 			seq_printf(m, "\t%ld", hd->cmd_cnt[x]);
2152*4882a593Smuzhiyun 		seq_puts(m, "\ndisconnects allowed:");
2153*4882a593Smuzhiyun 		for (x = 0; x < 7; x++)
2154*4882a593Smuzhiyun 			seq_printf(m, "\t%ld", hd->disc_allowed_cnt[x]);
2155*4882a593Smuzhiyun 		seq_puts(m, "\ndisconnects done:   ");
2156*4882a593Smuzhiyun 		for (x = 0; x < 7; x++)
2157*4882a593Smuzhiyun 			seq_printf(m, "\t%ld", hd->disc_done_cnt[x]);
2158*4882a593Smuzhiyun 		seq_printf(m,
2159*4882a593Smuzhiyun 			"\ninterrupts: %ld, DATA_PHASE ints: %ld DMA, %ld PIO",
2160*4882a593Smuzhiyun 			hd->int_cnt, hd->dma_cnt, hd->pio_cnt);
2161*4882a593Smuzhiyun 	}
2162*4882a593Smuzhiyun #endif
2163*4882a593Smuzhiyun 	if (hd->proc & PR_CONNECTED) {
2164*4882a593Smuzhiyun 		seq_puts(m, "\nconnected:     ");
2165*4882a593Smuzhiyun 		if (hd->connected) {
2166*4882a593Smuzhiyun 			cmd = (struct scsi_cmnd *) hd->connected;
2167*4882a593Smuzhiyun 			seq_printf(m, " %d:%llu(%02x)",
2168*4882a593Smuzhiyun 				cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
2169*4882a593Smuzhiyun 		}
2170*4882a593Smuzhiyun 	}
2171*4882a593Smuzhiyun 	if (hd->proc & PR_INPUTQ) {
2172*4882a593Smuzhiyun 		seq_puts(m, "\ninput_Q:       ");
2173*4882a593Smuzhiyun 		cmd = (struct scsi_cmnd *) hd->input_Q;
2174*4882a593Smuzhiyun 		while (cmd) {
2175*4882a593Smuzhiyun 			seq_printf(m, " %d:%llu(%02x)",
2176*4882a593Smuzhiyun 				cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
2177*4882a593Smuzhiyun 			cmd = (struct scsi_cmnd *) cmd->host_scribble;
2178*4882a593Smuzhiyun 		}
2179*4882a593Smuzhiyun 	}
2180*4882a593Smuzhiyun 	if (hd->proc & PR_DISCQ) {
2181*4882a593Smuzhiyun 		seq_puts(m, "\ndisconnected_Q:");
2182*4882a593Smuzhiyun 		cmd = (struct scsi_cmnd *) hd->disconnected_Q;
2183*4882a593Smuzhiyun 		while (cmd) {
2184*4882a593Smuzhiyun 			seq_printf(m, " %d:%llu(%02x)",
2185*4882a593Smuzhiyun 				cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
2186*4882a593Smuzhiyun 			cmd = (struct scsi_cmnd *) cmd->host_scribble;
2187*4882a593Smuzhiyun 		}
2188*4882a593Smuzhiyun 	}
2189*4882a593Smuzhiyun 	seq_putc(m, '\n');
2190*4882a593Smuzhiyun 	spin_unlock_irq(&hd->lock);
2191*4882a593Smuzhiyun #endif				/* PROC_INTERFACE */
2192*4882a593Smuzhiyun 	return 0;
2193*4882a593Smuzhiyun }
2194*4882a593Smuzhiyun 
2195*4882a593Smuzhiyun EXPORT_SYMBOL(wd33c93_host_reset);
2196*4882a593Smuzhiyun EXPORT_SYMBOL(wd33c93_init);
2197*4882a593Smuzhiyun EXPORT_SYMBOL(wd33c93_abort);
2198*4882a593Smuzhiyun EXPORT_SYMBOL(wd33c93_queuecommand);
2199*4882a593Smuzhiyun EXPORT_SYMBOL(wd33c93_intr);
2200*4882a593Smuzhiyun EXPORT_SYMBOL(wd33c93_show_info);
2201*4882a593Smuzhiyun EXPORT_SYMBOL(wd33c93_write_info);
2202