xref: /OK3568_Linux_fs/kernel/drivers/scsi/aha152x.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* aha152x.c -- Adaptec AHA-152x driver
3*4882a593Smuzhiyun  * Author: Jürgen E. Fischer, fischer@norbit.de
4*4882a593Smuzhiyun  * Copyright 1993-2004 Jürgen E. Fischer
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * $Log: aha152x.c,v $
9*4882a593Smuzhiyun  * Revision 2.7  2004/01/24 11:42:59  fischer
10*4882a593Smuzhiyun  * - gather code that is not used by PCMCIA at the end
11*4882a593Smuzhiyun  * - move request_region for !PCMCIA case to detection
12*4882a593Smuzhiyun  * - migration to new scsi host api (remove legacy code)
13*4882a593Smuzhiyun  * - free host scribble before scsi_done
14*4882a593Smuzhiyun  * - fix error handling
15*4882a593Smuzhiyun  * - one isapnp device added to id_table
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * Revision 2.6  2003/10/30 20:52:47  fischer
18*4882a593Smuzhiyun  * - interfaces changes for kernel 2.6
19*4882a593Smuzhiyun  * - aha152x_probe_one introduced for pcmcia stub
20*4882a593Smuzhiyun  * - fixed pnpdev handling
21*4882a593Smuzhiyun  * - instead of allocation a new one, reuse command for request sense after check condition and reset
22*4882a593Smuzhiyun  * - fixes race in is_complete
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * Revision 2.5  2002/04/14 11:24:53  fischer
25*4882a593Smuzhiyun  * - isapnp support
26*4882a593Smuzhiyun  * - abort fixed
27*4882a593Smuzhiyun  * - 2.5 support
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * Revision 2.4  2000/12/16 12:53:56  fischer
30*4882a593Smuzhiyun  * - allow REQUEST SENSE to be queued
31*4882a593Smuzhiyun  * - handle shared PCI interrupts
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * Revision 2.3  2000/11/04 16:40:26  fischer
34*4882a593Smuzhiyun  * - handle data overruns
35*4882a593Smuzhiyun  * - extend timeout for data phases
36*4882a593Smuzhiyun  *
37*4882a593Smuzhiyun  * Revision 2.2  2000/08/08 19:54:53  fischer
38*4882a593Smuzhiyun  * - minor changes
39*4882a593Smuzhiyun  *
40*4882a593Smuzhiyun  * Revision 2.1  2000/05/17 16:23:17  fischer
41*4882a593Smuzhiyun  * - signature update
42*4882a593Smuzhiyun  * - fix for data out w/o scatter gather
43*4882a593Smuzhiyun  *
44*4882a593Smuzhiyun  * Revision 2.0  1999/12/25 15:07:32  fischer
45*4882a593Smuzhiyun  * - interrupt routine completly reworked
46*4882a593Smuzhiyun  * - basic support for new eh code
47*4882a593Smuzhiyun  *
48*4882a593Smuzhiyun  * Revision 1.21  1999/11/10 23:46:36  fischer
49*4882a593Smuzhiyun  * - default to synchronous operation
50*4882a593Smuzhiyun  * - synchronous negotiation fixed
51*4882a593Smuzhiyun  * - added timeout to loops
52*4882a593Smuzhiyun  * - debugging output can be controlled through procfs
53*4882a593Smuzhiyun  *
54*4882a593Smuzhiyun  * Revision 1.20  1999/11/07 18:37:31  fischer
55*4882a593Smuzhiyun  * - synchronous operation works
56*4882a593Smuzhiyun  * - resid support for sg driver
57*4882a593Smuzhiyun  *
58*4882a593Smuzhiyun  * Revision 1.19  1999/11/02 22:39:59  fischer
59*4882a593Smuzhiyun  * - moved leading comments to README.aha152x
60*4882a593Smuzhiyun  * - new additional module parameters
61*4882a593Smuzhiyun  * - updates for 2.3
62*4882a593Smuzhiyun  * - support for the Tripace TC1550 controller
63*4882a593Smuzhiyun  * - interrupt handling changed
64*4882a593Smuzhiyun  *
65*4882a593Smuzhiyun  * Revision 1.18  1996/09/07 20:10:40  fischer
66*4882a593Smuzhiyun  * - fixed can_queue handling (multiple outstanding commands working again)
67*4882a593Smuzhiyun  *
68*4882a593Smuzhiyun  * Revision 1.17  1996/08/17 16:05:14  fischer
69*4882a593Smuzhiyun  * - biosparam improved
70*4882a593Smuzhiyun  * - interrupt verification
71*4882a593Smuzhiyun  * - updated documentation
72*4882a593Smuzhiyun  * - cleanups
73*4882a593Smuzhiyun  *
74*4882a593Smuzhiyun  * Revision 1.16  1996/06/09 00:04:56  root
75*4882a593Smuzhiyun  * - added configuration symbols for insmod (aha152x/aha152x1)
76*4882a593Smuzhiyun  *
77*4882a593Smuzhiyun  * Revision 1.15  1996/04/30 14:52:06  fischer
78*4882a593Smuzhiyun  * - proc info fixed
79*4882a593Smuzhiyun  * - support for extended translation for >1GB disks
80*4882a593Smuzhiyun  *
81*4882a593Smuzhiyun  * Revision 1.14  1996/01/17  15:11:20  fischer
82*4882a593Smuzhiyun  * - fixed lockup in MESSAGE IN phase after reconnection
83*4882a593Smuzhiyun  *
84*4882a593Smuzhiyun  * Revision 1.13  1996/01/09  02:15:53  fischer
85*4882a593Smuzhiyun  * - some cleanups
86*4882a593Smuzhiyun  * - moved request_irq behind controller initialization
87*4882a593Smuzhiyun  *   (to avoid spurious interrupts)
88*4882a593Smuzhiyun  *
89*4882a593Smuzhiyun  * Revision 1.12  1995/12/16  12:26:07  fischer
90*4882a593Smuzhiyun  * - barrier()s added
91*4882a593Smuzhiyun  * - configurable RESET delay added
92*4882a593Smuzhiyun  *
93*4882a593Smuzhiyun  * Revision 1.11  1995/12/06  21:18:35  fischer
94*4882a593Smuzhiyun  * - some minor updates
95*4882a593Smuzhiyun  *
96*4882a593Smuzhiyun  * Revision 1.10  1995/07/22  19:18:45  fischer
97*4882a593Smuzhiyun  * - support for 2 controllers
98*4882a593Smuzhiyun  * - started synchronous data transfers (not working yet)
99*4882a593Smuzhiyun  *
100*4882a593Smuzhiyun  * Revision 1.9  1995/03/18  09:20:24  root
101*4882a593Smuzhiyun  * - patches for PCMCIA and modules
102*4882a593Smuzhiyun  *
103*4882a593Smuzhiyun  * Revision 1.8  1995/01/21  22:07:19  root
104*4882a593Smuzhiyun  * - snarf_region => request_region
105*4882a593Smuzhiyun  * - aha152x_intr interface change
106*4882a593Smuzhiyun  *
107*4882a593Smuzhiyun  * Revision 1.7  1995/01/02  23:19:36  root
108*4882a593Smuzhiyun  * - updated COMMAND_SIZE to cmd_len
109*4882a593Smuzhiyun  * - changed sti() to restore_flags()
110*4882a593Smuzhiyun  * - fixed some #ifdef which generated warnings
111*4882a593Smuzhiyun  *
112*4882a593Smuzhiyun  * Revision 1.6  1994/11/24  20:35:27  root
113*4882a593Smuzhiyun  * - problem with odd number of bytes in fifo fixed
114*4882a593Smuzhiyun  *
115*4882a593Smuzhiyun  * Revision 1.5  1994/10/30  14:39:56  root
116*4882a593Smuzhiyun  * - abort code fixed
117*4882a593Smuzhiyun  * - debugging improved
118*4882a593Smuzhiyun  *
119*4882a593Smuzhiyun  * Revision 1.4  1994/09/12  11:33:01  root
120*4882a593Smuzhiyun  * - irqaction to request_irq
121*4882a593Smuzhiyun  * - abortion updated
122*4882a593Smuzhiyun  *
123*4882a593Smuzhiyun  * Revision 1.3  1994/08/04  13:53:05  root
124*4882a593Smuzhiyun  * - updates for mid-level-driver changes
125*4882a593Smuzhiyun  * - accept unexpected BUSFREE phase as error condition
126*4882a593Smuzhiyun  * - parity check now configurable
127*4882a593Smuzhiyun  *
128*4882a593Smuzhiyun  * Revision 1.2  1994/07/03  12:56:36  root
129*4882a593Smuzhiyun  * - cleaned up debugging code
130*4882a593Smuzhiyun  * - more tweaking on reset delays
131*4882a593Smuzhiyun  * - updated abort/reset code (pretty untested...)
132*4882a593Smuzhiyun  *
133*4882a593Smuzhiyun  * Revision 1.1  1994/05/28  21:18:49  root
134*4882a593Smuzhiyun  * - update for mid-level interface change (abort-reset)
135*4882a593Smuzhiyun  * - delays after resets adjusted for some slow devices
136*4882a593Smuzhiyun  *
137*4882a593Smuzhiyun  * Revision 1.0  1994/03/25  12:52:00  root
138*4882a593Smuzhiyun  * - Fixed "more data than expected" problem
139*4882a593Smuzhiyun  * - added new BIOS signatures
140*4882a593Smuzhiyun  *
141*4882a593Smuzhiyun  * Revision 0.102  1994/01/31  20:44:12  root
142*4882a593Smuzhiyun  * - minor changes in insw/outsw handling
143*4882a593Smuzhiyun  *
144*4882a593Smuzhiyun  * Revision 0.101  1993/12/13  01:16:27  root
145*4882a593Smuzhiyun  * - fixed STATUS phase (non-GOOD stati were dropped sometimes;
146*4882a593Smuzhiyun  *   fixes problems with CD-ROM sector size detection & media change)
147*4882a593Smuzhiyun  *
148*4882a593Smuzhiyun  * Revision 0.100  1993/12/10  16:58:47  root
149*4882a593Smuzhiyun  * - fix for unsuccessful selections in case of non-continuous id assignments
150*4882a593Smuzhiyun  *   on the scsi bus.
151*4882a593Smuzhiyun  *
152*4882a593Smuzhiyun  * Revision 0.99  1993/10/24  16:19:59  root
153*4882a593Smuzhiyun  * - fixed DATA IN (rare read errors gone)
154*4882a593Smuzhiyun  *
155*4882a593Smuzhiyun  * Revision 0.98  1993/10/17  12:54:44  root
156*4882a593Smuzhiyun  * - fixed some recent fixes (shame on me)
157*4882a593Smuzhiyun  * - moved initialization of scratch area to aha152x_queue
158*4882a593Smuzhiyun  *
159*4882a593Smuzhiyun  * Revision 0.97  1993/10/09  18:53:53  root
160*4882a593Smuzhiyun  * - DATA IN fixed. Rarely left data in the fifo.
161*4882a593Smuzhiyun  *
162*4882a593Smuzhiyun  * Revision 0.96  1993/10/03  00:53:59  root
163*4882a593Smuzhiyun  * - minor changes on DATA IN
164*4882a593Smuzhiyun  *
165*4882a593Smuzhiyun  * Revision 0.95  1993/09/24  10:36:01  root
166*4882a593Smuzhiyun  * - change handling of MSGI after reselection
167*4882a593Smuzhiyun  * - fixed sti/cli
168*4882a593Smuzhiyun  * - minor changes
169*4882a593Smuzhiyun  *
170*4882a593Smuzhiyun  * Revision 0.94  1993/09/18  14:08:22  root
171*4882a593Smuzhiyun  * - fixed bug in multiple outstanding command code
172*4882a593Smuzhiyun  * - changed detection
173*4882a593Smuzhiyun  * - support for kernel command line configuration
174*4882a593Smuzhiyun  * - reset corrected
175*4882a593Smuzhiyun  * - changed message handling
176*4882a593Smuzhiyun  *
177*4882a593Smuzhiyun  * Revision 0.93  1993/09/15  20:41:19  root
178*4882a593Smuzhiyun  * - fixed bugs with multiple outstanding commands
179*4882a593Smuzhiyun  *
180*4882a593Smuzhiyun  * Revision 0.92  1993/09/13  02:46:33  root
181*4882a593Smuzhiyun  * - multiple outstanding commands work (no problems with IBM drive)
182*4882a593Smuzhiyun  *
183*4882a593Smuzhiyun  * Revision 0.91  1993/09/12  20:51:46  root
184*4882a593Smuzhiyun  * added multiple outstanding commands
185*4882a593Smuzhiyun  * (some problem with this $%&? IBM device remain)
186*4882a593Smuzhiyun  *
187*4882a593Smuzhiyun  * Revision 0.9  1993/09/12  11:11:22  root
188*4882a593Smuzhiyun  * - corrected auto-configuration
189*4882a593Smuzhiyun  * - changed the auto-configuration (added some '#define's)
190*4882a593Smuzhiyun  * - added support for dis-/reconnection
191*4882a593Smuzhiyun  *
192*4882a593Smuzhiyun  * Revision 0.8  1993/09/06  23:09:39  root
193*4882a593Smuzhiyun  * - added support for the drive activity light
194*4882a593Smuzhiyun  * - minor changes
195*4882a593Smuzhiyun  *
196*4882a593Smuzhiyun  * Revision 0.7  1993/09/05  14:30:15  root
197*4882a593Smuzhiyun  * - improved phase detection
198*4882a593Smuzhiyun  * - now using the new snarf_region code of 0.99pl13
199*4882a593Smuzhiyun  *
200*4882a593Smuzhiyun  * Revision 0.6  1993/09/02  11:01:38  root
201*4882a593Smuzhiyun  * first public release; added some signatures and biosparam()
202*4882a593Smuzhiyun  *
203*4882a593Smuzhiyun  * Revision 0.5  1993/08/30  10:23:30  root
204*4882a593Smuzhiyun  * fixed timing problems with my IBM drive
205*4882a593Smuzhiyun  *
206*4882a593Smuzhiyun  * Revision 0.4  1993/08/29  14:06:52  root
207*4882a593Smuzhiyun  * fixed some problems with timeouts due incomplete commands
208*4882a593Smuzhiyun  *
209*4882a593Smuzhiyun  * Revision 0.3  1993/08/28  15:55:03  root
210*4882a593Smuzhiyun  * writing data works too.  mounted and worked on a dos partition
211*4882a593Smuzhiyun  *
212*4882a593Smuzhiyun  * Revision 0.2  1993/08/27  22:42:07  root
213*4882a593Smuzhiyun  * reading data works.  Mounted a msdos partition.
214*4882a593Smuzhiyun  *
215*4882a593Smuzhiyun  * Revision 0.1  1993/08/25  13:38:30  root
216*4882a593Smuzhiyun  * first "damn thing doesn't work" version
217*4882a593Smuzhiyun  *
218*4882a593Smuzhiyun  * Revision 0.0  1993/08/14  19:54:25  root
219*4882a593Smuzhiyun  * empty function bodies; detect() works.
220*4882a593Smuzhiyun  *
221*4882a593Smuzhiyun  **************************************************************************
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun  see Documentation/scsi/aha152x.rst for configuration details
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun  **************************************************************************/
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun #include <linux/module.h>
228*4882a593Smuzhiyun #include <asm/irq.h>
229*4882a593Smuzhiyun #include <linux/io.h>
230*4882a593Smuzhiyun #include <linux/blkdev.h>
231*4882a593Smuzhiyun #include <linux/completion.h>
232*4882a593Smuzhiyun #include <linux/errno.h>
233*4882a593Smuzhiyun #include <linux/string.h>
234*4882a593Smuzhiyun #include <linux/wait.h>
235*4882a593Smuzhiyun #include <linux/ioport.h>
236*4882a593Smuzhiyun #include <linux/delay.h>
237*4882a593Smuzhiyun #include <linux/proc_fs.h>
238*4882a593Smuzhiyun #include <linux/interrupt.h>
239*4882a593Smuzhiyun #include <linux/init.h>
240*4882a593Smuzhiyun #include <linux/kernel.h>
241*4882a593Smuzhiyun #include <linux/isapnp.h>
242*4882a593Smuzhiyun #include <linux/spinlock.h>
243*4882a593Smuzhiyun #include <linux/workqueue.h>
244*4882a593Smuzhiyun #include <linux/list.h>
245*4882a593Smuzhiyun #include <linux/slab.h>
246*4882a593Smuzhiyun #include <scsi/scsicam.h>
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun #include "scsi.h"
249*4882a593Smuzhiyun #include <scsi/scsi_dbg.h>
250*4882a593Smuzhiyun #include <scsi/scsi_host.h>
251*4882a593Smuzhiyun #include <scsi/scsi_transport_spi.h>
252*4882a593Smuzhiyun #include <scsi/scsi_eh.h>
253*4882a593Smuzhiyun #include "aha152x.h"
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun static LIST_HEAD(aha152x_host_list);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun /* DEFINES */
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun /* For PCMCIA cards, always use AUTOCONF */
261*4882a593Smuzhiyun #if defined(AHA152X_PCMCIA) || defined(MODULE)
262*4882a593Smuzhiyun #if !defined(AUTOCONF)
263*4882a593Smuzhiyun #define AUTOCONF
264*4882a593Smuzhiyun #endif
265*4882a593Smuzhiyun #endif
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun #if !defined(AUTOCONF) && !defined(SETUP0)
268*4882a593Smuzhiyun #error define AUTOCONF or SETUP0
269*4882a593Smuzhiyun #endif
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun #define	DO_LOCK(flags)		spin_lock_irqsave(&QLOCK,flags)
272*4882a593Smuzhiyun #define	DO_UNLOCK(flags)	spin_unlock_irqrestore(&QLOCK,flags)
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun #define LEAD		"(scsi%d:%d:%d) "
275*4882a593Smuzhiyun #define INFO_LEAD	KERN_INFO	LEAD
276*4882a593Smuzhiyun #define CMDINFO(cmd) \
277*4882a593Smuzhiyun 			(cmd) ? ((cmd)->device->host->host_no) : -1, \
278*4882a593Smuzhiyun                         (cmd) ? ((cmd)->device->id & 0x0f) : -1, \
279*4882a593Smuzhiyun 			(cmd) ? ((u8)(cmd)->device->lun & 0x07) : -1
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun static inline void
CMD_INC_RESID(struct scsi_cmnd * cmd,int inc)282*4882a593Smuzhiyun CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	scsi_set_resid(cmd, scsi_get_resid(cmd) + inc);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun #define DELAY_DEFAULT 1000
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun #if defined(AHA152X_PCMCIA)
290*4882a593Smuzhiyun #define IRQ_MIN 0
291*4882a593Smuzhiyun #define IRQ_MAX 16
292*4882a593Smuzhiyun #else
293*4882a593Smuzhiyun #define IRQ_MIN 9
294*4882a593Smuzhiyun #if defined(__PPC)
295*4882a593Smuzhiyun #define IRQ_MAX (nr_irqs-1)
296*4882a593Smuzhiyun #else
297*4882a593Smuzhiyun #define IRQ_MAX 12
298*4882a593Smuzhiyun #endif
299*4882a593Smuzhiyun #endif
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun enum {
302*4882a593Smuzhiyun 	not_issued	= 0x0001,	/* command not yet issued */
303*4882a593Smuzhiyun 	selecting	= 0x0002,	/* target is being selected */
304*4882a593Smuzhiyun 	identified	= 0x0004,	/* IDENTIFY was sent */
305*4882a593Smuzhiyun 	disconnected	= 0x0008,	/* target disconnected */
306*4882a593Smuzhiyun 	completed	= 0x0010,	/* target sent COMMAND COMPLETE */
307*4882a593Smuzhiyun 	aborted		= 0x0020,	/* ABORT was sent */
308*4882a593Smuzhiyun 	resetted	= 0x0040,	/* BUS DEVICE RESET was sent */
309*4882a593Smuzhiyun 	spiordy		= 0x0080,	/* waiting for SPIORDY to raise */
310*4882a593Smuzhiyun 	syncneg		= 0x0100,	/* synchronous negotiation in progress */
311*4882a593Smuzhiyun 	aborting	= 0x0200,	/* ABORT is pending */
312*4882a593Smuzhiyun 	resetting	= 0x0400,	/* BUS DEVICE RESET is pending */
313*4882a593Smuzhiyun 	check_condition = 0x0800,	/* requesting sense after CHECK CONDITION */
314*4882a593Smuzhiyun };
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun MODULE_AUTHOR("Jürgen Fischer");
317*4882a593Smuzhiyun MODULE_DESCRIPTION(AHA152X_REVID);
318*4882a593Smuzhiyun MODULE_LICENSE("GPL");
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun #if !defined(AHA152X_PCMCIA)
321*4882a593Smuzhiyun #if defined(MODULE)
322*4882a593Smuzhiyun static int io[] = {0, 0};
323*4882a593Smuzhiyun module_param_hw_array(io, int, ioport, NULL, 0);
324*4882a593Smuzhiyun MODULE_PARM_DESC(io,"base io address of controller");
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun static int irq[] = {0, 0};
327*4882a593Smuzhiyun module_param_hw_array(irq, int, irq, NULL, 0);
328*4882a593Smuzhiyun MODULE_PARM_DESC(irq,"interrupt for controller");
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun static int scsiid[] = {7, 7};
331*4882a593Smuzhiyun module_param_array(scsiid, int, NULL, 0);
332*4882a593Smuzhiyun MODULE_PARM_DESC(scsiid,"scsi id of controller");
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun static int reconnect[] = {1, 1};
335*4882a593Smuzhiyun module_param_array(reconnect, int, NULL, 0);
336*4882a593Smuzhiyun MODULE_PARM_DESC(reconnect,"allow targets to disconnect");
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun static int parity[] = {1, 1};
339*4882a593Smuzhiyun module_param_array(parity, int, NULL, 0);
340*4882a593Smuzhiyun MODULE_PARM_DESC(parity,"use scsi parity");
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun static int sync[] = {1, 1};
343*4882a593Smuzhiyun module_param_array(sync, int, NULL, 0);
344*4882a593Smuzhiyun MODULE_PARM_DESC(sync,"use synchronous transfers");
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
347*4882a593Smuzhiyun module_param_array(delay, int, NULL, 0);
348*4882a593Smuzhiyun MODULE_PARM_DESC(delay,"scsi reset delay");
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun static int exttrans[] = {0, 0};
351*4882a593Smuzhiyun module_param_array(exttrans, int, NULL, 0);
352*4882a593Smuzhiyun MODULE_PARM_DESC(exttrans,"use extended translation");
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
355*4882a593Smuzhiyun module_param_array(aha152x, int, NULL, 0);
356*4882a593Smuzhiyun MODULE_PARM_DESC(aha152x, "parameters for first controller");
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
359*4882a593Smuzhiyun module_param_array(aha152x1, int, NULL, 0);
360*4882a593Smuzhiyun MODULE_PARM_DESC(aha152x1, "parameters for second controller");
361*4882a593Smuzhiyun #endif /* MODULE */
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun #ifdef __ISAPNP__
364*4882a593Smuzhiyun static struct isapnp_device_id id_table[] = {
365*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 },
366*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 },
367*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 },
368*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 },
369*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 },
370*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 },
371*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 },
372*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 },
373*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 },
374*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 },
375*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 },
376*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 },
377*4882a593Smuzhiyun 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,	ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 },
378*4882a593Smuzhiyun 	{ ISAPNP_DEVICE_SINGLE_END, }
379*4882a593Smuzhiyun };
380*4882a593Smuzhiyun MODULE_DEVICE_TABLE(isapnp, id_table);
381*4882a593Smuzhiyun #endif /* ISAPNP */
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun #endif /* !AHA152X_PCMCIA */
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun static struct scsi_host_template aha152x_driver_template;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun /*
388*4882a593Smuzhiyun  * internal states of the host
389*4882a593Smuzhiyun  *
390*4882a593Smuzhiyun  */
391*4882a593Smuzhiyun enum aha152x_state {
392*4882a593Smuzhiyun 	idle=0,
393*4882a593Smuzhiyun 	unknown,
394*4882a593Smuzhiyun 	seldo,
395*4882a593Smuzhiyun 	seldi,
396*4882a593Smuzhiyun 	selto,
397*4882a593Smuzhiyun 	busfree,
398*4882a593Smuzhiyun 	msgo,
399*4882a593Smuzhiyun 	cmd,
400*4882a593Smuzhiyun 	msgi,
401*4882a593Smuzhiyun 	status,
402*4882a593Smuzhiyun 	datai,
403*4882a593Smuzhiyun 	datao,
404*4882a593Smuzhiyun 	parerr,
405*4882a593Smuzhiyun 	rsti,
406*4882a593Smuzhiyun 	maxstate
407*4882a593Smuzhiyun };
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun /*
410*4882a593Smuzhiyun  * current state information of the host
411*4882a593Smuzhiyun  *
412*4882a593Smuzhiyun  */
413*4882a593Smuzhiyun struct aha152x_hostdata {
414*4882a593Smuzhiyun 	struct scsi_cmnd *issue_SC;
415*4882a593Smuzhiyun 		/* pending commands to issue */
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	struct scsi_cmnd *current_SC;
418*4882a593Smuzhiyun 		/* current command on the bus */
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	struct scsi_cmnd *disconnected_SC;
421*4882a593Smuzhiyun 		/* commands that disconnected */
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	struct scsi_cmnd *done_SC;
424*4882a593Smuzhiyun 		/* command that was completed */
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	spinlock_t lock;
427*4882a593Smuzhiyun 		/* host lock */
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun #if defined(AHA152X_STAT)
430*4882a593Smuzhiyun 	int	      total_commands;
431*4882a593Smuzhiyun 	int	      disconnections;
432*4882a593Smuzhiyun 	int	      busfree_without_any_action;
433*4882a593Smuzhiyun 	int	      busfree_without_old_command;
434*4882a593Smuzhiyun 	int	      busfree_without_new_command;
435*4882a593Smuzhiyun 	int	      busfree_without_done_command;
436*4882a593Smuzhiyun 	int	      busfree_with_check_condition;
437*4882a593Smuzhiyun 	int	      count[maxstate];
438*4882a593Smuzhiyun 	int	      count_trans[maxstate];
439*4882a593Smuzhiyun 	unsigned long time[maxstate];
440*4882a593Smuzhiyun #endif
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	int commands;		/* current number of commands */
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	int reconnect;		/* disconnection allowed */
445*4882a593Smuzhiyun 	int parity;		/* parity checking enabled */
446*4882a593Smuzhiyun 	int synchronous;	/* synchronous transferes enabled */
447*4882a593Smuzhiyun 	int delay;		/* reset out delay */
448*4882a593Smuzhiyun 	int ext_trans;		/* extended translation enabled */
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	int swint;		/* software-interrupt was fired during detect() */
451*4882a593Smuzhiyun 	int service;		/* bh needs to be run */
452*4882a593Smuzhiyun 	int in_intr;		/* bh is running */
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	/* current state,
455*4882a593Smuzhiyun 	   previous state,
456*4882a593Smuzhiyun 	   last state different from current state */
457*4882a593Smuzhiyun 	enum aha152x_state state, prevstate, laststate;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	int target;
460*4882a593Smuzhiyun 		/* reconnecting target */
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	unsigned char syncrate[8];
463*4882a593Smuzhiyun 		/* current synchronous transfer agreements */
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	unsigned char syncneg[8];
466*4882a593Smuzhiyun 		/* 0: no negotiation;
467*4882a593Smuzhiyun 		 * 1: negotiation in progress;
468*4882a593Smuzhiyun 		 * 2: negotiation completed
469*4882a593Smuzhiyun 		 */
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	int cmd_i;
472*4882a593Smuzhiyun 		/* number of sent bytes of current command */
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	int msgi_len;
475*4882a593Smuzhiyun 		/* number of received message bytes */
476*4882a593Smuzhiyun 	unsigned char msgi[256];
477*4882a593Smuzhiyun 		/* received message bytes */
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	int msgo_i, msgo_len;
480*4882a593Smuzhiyun 		/* number of sent bytes and length of current messages */
481*4882a593Smuzhiyun 	unsigned char msgo[256];
482*4882a593Smuzhiyun 		/* pending messages */
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	int data_len;
485*4882a593Smuzhiyun 		/* number of sent/received bytes in dataphase */
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	unsigned long io_port0;
488*4882a593Smuzhiyun 	unsigned long io_port1;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun #ifdef __ISAPNP__
491*4882a593Smuzhiyun 	struct pnp_dev *pnpdev;
492*4882a593Smuzhiyun #endif
493*4882a593Smuzhiyun 	struct list_head host_list;
494*4882a593Smuzhiyun };
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun /*
498*4882a593Smuzhiyun  * host specific command extension
499*4882a593Smuzhiyun  *
500*4882a593Smuzhiyun  */
501*4882a593Smuzhiyun struct aha152x_scdata {
502*4882a593Smuzhiyun 	struct scsi_cmnd *next;	/* next sc in queue */
503*4882a593Smuzhiyun 	struct completion *done;/* semaphore to block on */
504*4882a593Smuzhiyun 	struct scsi_eh_save ses;
505*4882a593Smuzhiyun };
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun /* access macros for hostdata */
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun #define HOSTDATA(shpnt)		((struct aha152x_hostdata *) &shpnt->hostdata)
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun #define HOSTNO			((shpnt)->host_no)
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun #define CURRENT_SC		(HOSTDATA(shpnt)->current_SC)
514*4882a593Smuzhiyun #define DONE_SC			(HOSTDATA(shpnt)->done_SC)
515*4882a593Smuzhiyun #define ISSUE_SC		(HOSTDATA(shpnt)->issue_SC)
516*4882a593Smuzhiyun #define DISCONNECTED_SC		(HOSTDATA(shpnt)->disconnected_SC)
517*4882a593Smuzhiyun #define QLOCK			(HOSTDATA(shpnt)->lock)
518*4882a593Smuzhiyun #define QLOCKER			(HOSTDATA(shpnt)->locker)
519*4882a593Smuzhiyun #define QLOCKERL		(HOSTDATA(shpnt)->lockerl)
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun #define STATE			(HOSTDATA(shpnt)->state)
522*4882a593Smuzhiyun #define PREVSTATE		(HOSTDATA(shpnt)->prevstate)
523*4882a593Smuzhiyun #define LASTSTATE		(HOSTDATA(shpnt)->laststate)
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun #define RECONN_TARGET		(HOSTDATA(shpnt)->target)
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun #define CMD_I			(HOSTDATA(shpnt)->cmd_i)
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun #define MSGO(i)			(HOSTDATA(shpnt)->msgo[i])
530*4882a593Smuzhiyun #define MSGO_I			(HOSTDATA(shpnt)->msgo_i)
531*4882a593Smuzhiyun #define MSGOLEN			(HOSTDATA(shpnt)->msgo_len)
532*4882a593Smuzhiyun #define ADDMSGO(x)		(MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun #define MSGI(i)			(HOSTDATA(shpnt)->msgi[i])
535*4882a593Smuzhiyun #define MSGILEN			(HOSTDATA(shpnt)->msgi_len)
536*4882a593Smuzhiyun #define ADDMSGI(x)		(MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun #define DATA_LEN		(HOSTDATA(shpnt)->data_len)
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun #define SYNCRATE		(HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])
541*4882a593Smuzhiyun #define SYNCNEG			(HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun #define DELAY			(HOSTDATA(shpnt)->delay)
544*4882a593Smuzhiyun #define EXT_TRANS		(HOSTDATA(shpnt)->ext_trans)
545*4882a593Smuzhiyun #define TC1550			(HOSTDATA(shpnt)->tc1550)
546*4882a593Smuzhiyun #define RECONNECT		(HOSTDATA(shpnt)->reconnect)
547*4882a593Smuzhiyun #define PARITY			(HOSTDATA(shpnt)->parity)
548*4882a593Smuzhiyun #define SYNCHRONOUS		(HOSTDATA(shpnt)->synchronous)
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun #define HOSTIOPORT0		(HOSTDATA(shpnt)->io_port0)
551*4882a593Smuzhiyun #define HOSTIOPORT1		(HOSTDATA(shpnt)->io_port1)
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun #define SCDATA(SCpnt)		((struct aha152x_scdata *) (SCpnt)->host_scribble)
554*4882a593Smuzhiyun #define SCNEXT(SCpnt)		SCDATA(SCpnt)->next
555*4882a593Smuzhiyun #define SCSEM(SCpnt)		SCDATA(SCpnt)->done
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun #define SG_ADDRESS(buffer)	((char *) sg_virt((buffer)))
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun /* state handling */
560*4882a593Smuzhiyun static void seldi_run(struct Scsi_Host *shpnt);
561*4882a593Smuzhiyun static void seldo_run(struct Scsi_Host *shpnt);
562*4882a593Smuzhiyun static void selto_run(struct Scsi_Host *shpnt);
563*4882a593Smuzhiyun static void busfree_run(struct Scsi_Host *shpnt);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun static void msgo_init(struct Scsi_Host *shpnt);
566*4882a593Smuzhiyun static void msgo_run(struct Scsi_Host *shpnt);
567*4882a593Smuzhiyun static void msgo_end(struct Scsi_Host *shpnt);
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun static void cmd_init(struct Scsi_Host *shpnt);
570*4882a593Smuzhiyun static void cmd_run(struct Scsi_Host *shpnt);
571*4882a593Smuzhiyun static void cmd_end(struct Scsi_Host *shpnt);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun static void datai_init(struct Scsi_Host *shpnt);
574*4882a593Smuzhiyun static void datai_run(struct Scsi_Host *shpnt);
575*4882a593Smuzhiyun static void datai_end(struct Scsi_Host *shpnt);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun static void datao_init(struct Scsi_Host *shpnt);
578*4882a593Smuzhiyun static void datao_run(struct Scsi_Host *shpnt);
579*4882a593Smuzhiyun static void datao_end(struct Scsi_Host *shpnt);
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun static void status_run(struct Scsi_Host *shpnt);
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun static void msgi_run(struct Scsi_Host *shpnt);
584*4882a593Smuzhiyun static void msgi_end(struct Scsi_Host *shpnt);
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun static void parerr_run(struct Scsi_Host *shpnt);
587*4882a593Smuzhiyun static void rsti_run(struct Scsi_Host *shpnt);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun static void is_complete(struct Scsi_Host *shpnt);
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun /*
592*4882a593Smuzhiyun  * driver states
593*4882a593Smuzhiyun  *
594*4882a593Smuzhiyun  */
595*4882a593Smuzhiyun static struct {
596*4882a593Smuzhiyun 	char		*name;
597*4882a593Smuzhiyun 	void		(*init)(struct Scsi_Host *);
598*4882a593Smuzhiyun 	void		(*run)(struct Scsi_Host *);
599*4882a593Smuzhiyun 	void		(*end)(struct Scsi_Host *);
600*4882a593Smuzhiyun 	int		spio;
601*4882a593Smuzhiyun } states[] = {
602*4882a593Smuzhiyun 	{ "idle",	NULL,		NULL,		NULL,		0},
603*4882a593Smuzhiyun 	{ "unknown",	NULL,		NULL,		NULL,		0},
604*4882a593Smuzhiyun 	{ "seldo",	NULL,		seldo_run,	NULL,		0},
605*4882a593Smuzhiyun 	{ "seldi",	NULL,		seldi_run,	NULL,		0},
606*4882a593Smuzhiyun 	{ "selto",	NULL,		selto_run,	NULL,		0},
607*4882a593Smuzhiyun 	{ "busfree",	NULL,		busfree_run,	NULL,		0},
608*4882a593Smuzhiyun 	{ "msgo",	msgo_init,	msgo_run,	msgo_end,	1},
609*4882a593Smuzhiyun 	{ "cmd",	cmd_init,	cmd_run,	cmd_end,	1},
610*4882a593Smuzhiyun 	{ "msgi",	NULL,		msgi_run,	msgi_end,	1},
611*4882a593Smuzhiyun 	{ "status",	NULL,		status_run,	NULL,		1},
612*4882a593Smuzhiyun 	{ "datai",	datai_init,	datai_run,	datai_end,	0},
613*4882a593Smuzhiyun 	{ "datao",	datao_init,	datao_run,	datao_end,	0},
614*4882a593Smuzhiyun 	{ "parerr",	NULL,		parerr_run,	NULL,		0},
615*4882a593Smuzhiyun 	{ "rsti",	NULL,		rsti_run,	NULL,		0},
616*4882a593Smuzhiyun };
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun /* setup & interrupt */
619*4882a593Smuzhiyun static irqreturn_t intr(int irq, void *dev_id);
620*4882a593Smuzhiyun static void reset_ports(struct Scsi_Host *shpnt);
621*4882a593Smuzhiyun static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
622*4882a593Smuzhiyun static void done(struct Scsi_Host *shpnt, int error);
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun /* diagnostics */
625*4882a593Smuzhiyun static void show_command(struct scsi_cmnd * ptr);
626*4882a593Smuzhiyun static void show_queues(struct Scsi_Host *shpnt);
627*4882a593Smuzhiyun static void disp_enintr(struct Scsi_Host *shpnt);
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun /*
631*4882a593Smuzhiyun  *  queue services:
632*4882a593Smuzhiyun  *
633*4882a593Smuzhiyun  */
append_SC(struct scsi_cmnd ** SC,struct scsi_cmnd * new_SC)634*4882a593Smuzhiyun static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun 	struct scsi_cmnd *end;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	SCNEXT(new_SC) = NULL;
639*4882a593Smuzhiyun 	if (!*SC)
640*4882a593Smuzhiyun 		*SC = new_SC;
641*4882a593Smuzhiyun 	else {
642*4882a593Smuzhiyun 		for (end = *SC; SCNEXT(end); end = SCNEXT(end))
643*4882a593Smuzhiyun 			;
644*4882a593Smuzhiyun 		SCNEXT(end) = new_SC;
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun 
remove_first_SC(struct scsi_cmnd ** SC)648*4882a593Smuzhiyun static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd ** SC)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun 	struct scsi_cmnd *ptr;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	ptr = *SC;
653*4882a593Smuzhiyun 	if (ptr) {
654*4882a593Smuzhiyun 		*SC = SCNEXT(*SC);
655*4882a593Smuzhiyun 		SCNEXT(ptr)=NULL;
656*4882a593Smuzhiyun 	}
657*4882a593Smuzhiyun 	return ptr;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun 
remove_lun_SC(struct scsi_cmnd ** SC,int target,int lun)660*4882a593Smuzhiyun static inline struct scsi_cmnd *remove_lun_SC(struct scsi_cmnd ** SC,
661*4882a593Smuzhiyun 					      int target, int lun)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun 	struct scsi_cmnd *ptr, *prev;
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	for (ptr = *SC, prev = NULL;
666*4882a593Smuzhiyun 	     ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
667*4882a593Smuzhiyun 	     prev = ptr, ptr = SCNEXT(ptr))
668*4882a593Smuzhiyun 	     ;
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	if (ptr) {
671*4882a593Smuzhiyun 		if (prev)
672*4882a593Smuzhiyun 			SCNEXT(prev) = SCNEXT(ptr);
673*4882a593Smuzhiyun 		else
674*4882a593Smuzhiyun 			*SC = SCNEXT(ptr);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 		SCNEXT(ptr)=NULL;
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	return ptr;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun 
remove_SC(struct scsi_cmnd ** SC,struct scsi_cmnd * SCp)682*4882a593Smuzhiyun static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC,
683*4882a593Smuzhiyun 					  struct scsi_cmnd *SCp)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun 	struct scsi_cmnd *ptr, *prev;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	for (ptr = *SC, prev = NULL;
688*4882a593Smuzhiyun 	     ptr && SCp!=ptr;
689*4882a593Smuzhiyun 	     prev = ptr, ptr = SCNEXT(ptr))
690*4882a593Smuzhiyun 	     ;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	if (ptr) {
693*4882a593Smuzhiyun 		if (prev)
694*4882a593Smuzhiyun 			SCNEXT(prev) = SCNEXT(ptr);
695*4882a593Smuzhiyun 		else
696*4882a593Smuzhiyun 			*SC = SCNEXT(ptr);
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 		SCNEXT(ptr)=NULL;
699*4882a593Smuzhiyun 	}
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	return ptr;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
swintr(int irqno,void * dev_id)704*4882a593Smuzhiyun static irqreturn_t swintr(int irqno, void *dev_id)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	struct Scsi_Host *shpnt = dev_id;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	HOSTDATA(shpnt)->swint++;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, INTEN);
711*4882a593Smuzhiyun 	return IRQ_HANDLED;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun 
aha152x_probe_one(struct aha152x_setup * setup)714*4882a593Smuzhiyun struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun 	struct Scsi_Host *shpnt;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));
719*4882a593Smuzhiyun 	if (!shpnt) {
720*4882a593Smuzhiyun 		printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");
721*4882a593Smuzhiyun 		return NULL;
722*4882a593Smuzhiyun 	}
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
725*4882a593Smuzhiyun 	INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	/* need to have host registered before triggering any interrupt */
728*4882a593Smuzhiyun 	list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	shpnt->io_port   = setup->io_port;
731*4882a593Smuzhiyun 	shpnt->n_io_port = IO_RANGE;
732*4882a593Smuzhiyun 	shpnt->irq       = setup->irq;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	if (!setup->tc1550) {
735*4882a593Smuzhiyun 		HOSTIOPORT0 = setup->io_port;
736*4882a593Smuzhiyun 		HOSTIOPORT1 = setup->io_port;
737*4882a593Smuzhiyun 	} else {
738*4882a593Smuzhiyun 		HOSTIOPORT0 = setup->io_port+0x10;
739*4882a593Smuzhiyun 		HOSTIOPORT1 = setup->io_port-0x10;
740*4882a593Smuzhiyun 	}
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	spin_lock_init(&QLOCK);
743*4882a593Smuzhiyun 	RECONNECT   = setup->reconnect;
744*4882a593Smuzhiyun 	SYNCHRONOUS = setup->synchronous;
745*4882a593Smuzhiyun 	PARITY      = setup->parity;
746*4882a593Smuzhiyun 	DELAY       = setup->delay;
747*4882a593Smuzhiyun 	EXT_TRANS   = setup->ext_trans;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	SETPORT(SCSIID, setup->scsiid << 4);
750*4882a593Smuzhiyun 	shpnt->this_id = setup->scsiid;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	if (setup->reconnect)
753*4882a593Smuzhiyun 		shpnt->can_queue = AHA152X_MAXQUEUE;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	/* RESET OUT */
756*4882a593Smuzhiyun 	printk("aha152x: resetting bus...\n");
757*4882a593Smuzhiyun 	SETPORT(SCSISEQ, SCSIRSTO);
758*4882a593Smuzhiyun 	mdelay(256);
759*4882a593Smuzhiyun 	SETPORT(SCSISEQ, 0);
760*4882a593Smuzhiyun 	mdelay(DELAY);
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	reset_ports(shpnt);
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	printk(KERN_INFO
765*4882a593Smuzhiyun 	       "aha152x%d%s: "
766*4882a593Smuzhiyun 	       "vital data: rev=%x, "
767*4882a593Smuzhiyun 	       "io=0x%03lx (0x%03lx/0x%03lx), "
768*4882a593Smuzhiyun 	       "irq=%d, "
769*4882a593Smuzhiyun 	       "scsiid=%d, "
770*4882a593Smuzhiyun 	       "reconnect=%s, "
771*4882a593Smuzhiyun 	       "parity=%s, "
772*4882a593Smuzhiyun 	       "synchronous=%s, "
773*4882a593Smuzhiyun 	       "delay=%d, "
774*4882a593Smuzhiyun 	       "extended translation=%s\n",
775*4882a593Smuzhiyun 	       shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "",
776*4882a593Smuzhiyun 	       GETPORT(REV) & 0x7,
777*4882a593Smuzhiyun 	       shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
778*4882a593Smuzhiyun 	       shpnt->irq,
779*4882a593Smuzhiyun 	       shpnt->this_id,
780*4882a593Smuzhiyun 	       RECONNECT ? "enabled" : "disabled",
781*4882a593Smuzhiyun 	       PARITY ? "enabled" : "disabled",
782*4882a593Smuzhiyun 	       SYNCHRONOUS ? "enabled" : "disabled",
783*4882a593Smuzhiyun 	       DELAY,
784*4882a593Smuzhiyun 	       EXT_TRANS ? "enabled" : "disabled");
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	/* not expecting any interrupts */
787*4882a593Smuzhiyun 	SETPORT(SIMODE0, 0);
788*4882a593Smuzhiyun 	SETPORT(SIMODE1, 0);
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) {
791*4882a593Smuzhiyun 		printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
792*4882a593Smuzhiyun 		goto out_host_put;
793*4882a593Smuzhiyun 	}
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	HOSTDATA(shpnt)->swint = 0;
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no);
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	mb();
800*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, SWINT|INTEN);
801*4882a593Smuzhiyun 	mdelay(1000);
802*4882a593Smuzhiyun 	free_irq(shpnt->irq, shpnt);
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	if (!HOSTDATA(shpnt)->swint) {
805*4882a593Smuzhiyun 		if (TESTHI(DMASTAT, INTSTAT)) {
806*4882a593Smuzhiyun 			printk("lost.\n");
807*4882a593Smuzhiyun 		} else {
808*4882a593Smuzhiyun 			printk("failed.\n");
809*4882a593Smuzhiyun 		}
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 		SETPORT(DMACNTRL0, INTEN);
812*4882a593Smuzhiyun 
813*4882a593Smuzhiyun 		printk(KERN_ERR "aha152x%d: irq %d possibly wrong.  "
814*4882a593Smuzhiyun 				"Please verify.\n", shpnt->host_no, shpnt->irq);
815*4882a593Smuzhiyun 		goto out_host_put;
816*4882a593Smuzhiyun 	}
817*4882a593Smuzhiyun 	printk("ok.\n");
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	/* clear interrupts */
821*4882a593Smuzhiyun 	SETPORT(SSTAT0, 0x7f);
822*4882a593Smuzhiyun 	SETPORT(SSTAT1, 0xef);
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun 	if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) {
825*4882a593Smuzhiyun 		printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
826*4882a593Smuzhiyun 		goto out_host_put;
827*4882a593Smuzhiyun 	}
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	if( scsi_add_host(shpnt, NULL) ) {
830*4882a593Smuzhiyun 		free_irq(shpnt->irq, shpnt);
831*4882a593Smuzhiyun 		printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no);
832*4882a593Smuzhiyun 		goto out_host_put;
833*4882a593Smuzhiyun 	}
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	scsi_scan_host(shpnt);
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	return shpnt;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun out_host_put:
840*4882a593Smuzhiyun 	list_del(&HOSTDATA(shpnt)->host_list);
841*4882a593Smuzhiyun 	scsi_host_put(shpnt);
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	return NULL;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun 
aha152x_release(struct Scsi_Host * shpnt)846*4882a593Smuzhiyun void aha152x_release(struct Scsi_Host *shpnt)
847*4882a593Smuzhiyun {
848*4882a593Smuzhiyun 	if (!shpnt)
849*4882a593Smuzhiyun 		return;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 	scsi_remove_host(shpnt);
852*4882a593Smuzhiyun 	if (shpnt->irq)
853*4882a593Smuzhiyun 		free_irq(shpnt->irq, shpnt);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun #if !defined(AHA152X_PCMCIA)
856*4882a593Smuzhiyun 	if (shpnt->io_port)
857*4882a593Smuzhiyun 		release_region(shpnt->io_port, IO_RANGE);
858*4882a593Smuzhiyun #endif
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun #ifdef __ISAPNP__
861*4882a593Smuzhiyun 	if (HOSTDATA(shpnt)->pnpdev)
862*4882a593Smuzhiyun 		pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
863*4882a593Smuzhiyun #endif
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	list_del(&HOSTDATA(shpnt)->host_list);
866*4882a593Smuzhiyun 	scsi_host_put(shpnt);
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun /*
871*4882a593Smuzhiyun  * setup controller to generate interrupts depending
872*4882a593Smuzhiyun  * on current state (lock has to be acquired)
873*4882a593Smuzhiyun  *
874*4882a593Smuzhiyun  */
setup_expected_interrupts(struct Scsi_Host * shpnt)875*4882a593Smuzhiyun static int setup_expected_interrupts(struct Scsi_Host *shpnt)
876*4882a593Smuzhiyun {
877*4882a593Smuzhiyun 	if(CURRENT_SC) {
878*4882a593Smuzhiyun 		CURRENT_SC->SCp.phase |= 1 << 16;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 		if(CURRENT_SC->SCp.phase & selecting) {
881*4882a593Smuzhiyun 			SETPORT(SSTAT1, SELTO);
882*4882a593Smuzhiyun 			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
883*4882a593Smuzhiyun 			SETPORT(SIMODE1, ENSELTIMO);
884*4882a593Smuzhiyun 		} else {
885*4882a593Smuzhiyun 			SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);
886*4882a593Smuzhiyun 			SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
887*4882a593Smuzhiyun 		}
888*4882a593Smuzhiyun 	} else if(STATE==seldi) {
889*4882a593Smuzhiyun 		SETPORT(SIMODE0, 0);
890*4882a593Smuzhiyun 		SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
891*4882a593Smuzhiyun 	} else {
892*4882a593Smuzhiyun 		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
893*4882a593Smuzhiyun 		SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
894*4882a593Smuzhiyun 	}
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	if(!HOSTDATA(shpnt)->in_intr)
897*4882a593Smuzhiyun 		SETBITS(DMACNTRL0, INTEN);
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	return TESTHI(DMASTAT, INTSTAT);
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun /*
904*4882a593Smuzhiyun  *  Queue a command and setup interrupts for a free bus.
905*4882a593Smuzhiyun  */
aha152x_internal_queue(struct scsi_cmnd * SCpnt,struct completion * complete,int phase,void (* done)(struct scsi_cmnd *))906*4882a593Smuzhiyun static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
907*4882a593Smuzhiyun 				  struct completion *complete,
908*4882a593Smuzhiyun 				  int phase, void (*done)(struct scsi_cmnd *))
909*4882a593Smuzhiyun {
910*4882a593Smuzhiyun 	struct Scsi_Host *shpnt = SCpnt->device->host;
911*4882a593Smuzhiyun 	unsigned long flags;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	SCpnt->scsi_done	= done;
914*4882a593Smuzhiyun 	SCpnt->SCp.phase	= not_issued | phase;
915*4882a593Smuzhiyun 	SCpnt->SCp.Status	= 0x1; /* Ilegal status by SCSI standard */
916*4882a593Smuzhiyun 	SCpnt->SCp.Message	= 0;
917*4882a593Smuzhiyun 	SCpnt->SCp.have_data_in	= 0;
918*4882a593Smuzhiyun 	SCpnt->SCp.sent_command	= 0;
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	if(SCpnt->SCp.phase & (resetting|check_condition)) {
921*4882a593Smuzhiyun 		if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
922*4882a593Smuzhiyun 			scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n");
923*4882a593Smuzhiyun 			return FAILED;
924*4882a593Smuzhiyun 		}
925*4882a593Smuzhiyun 	} else {
926*4882a593Smuzhiyun 		SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
927*4882a593Smuzhiyun 		if(!SCpnt->host_scribble) {
928*4882a593Smuzhiyun 			scmd_printk(KERN_ERR, SCpnt, "allocation failed\n");
929*4882a593Smuzhiyun 			return FAILED;
930*4882a593Smuzhiyun 		}
931*4882a593Smuzhiyun 	}
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	SCNEXT(SCpnt)		= NULL;
934*4882a593Smuzhiyun 	SCSEM(SCpnt)		= complete;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	/* setup scratch area
937*4882a593Smuzhiyun 	   SCp.ptr              : buffer pointer
938*4882a593Smuzhiyun 	   SCp.this_residual    : buffer length
939*4882a593Smuzhiyun 	   SCp.buffer           : next buffer
940*4882a593Smuzhiyun 	   SCp.phase            : current state of the command */
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	if ((phase & resetting) || !scsi_sglist(SCpnt)) {
943*4882a593Smuzhiyun 		SCpnt->SCp.ptr           = NULL;
944*4882a593Smuzhiyun 		SCpnt->SCp.this_residual = 0;
945*4882a593Smuzhiyun 		scsi_set_resid(SCpnt, 0);
946*4882a593Smuzhiyun 		SCpnt->SCp.buffer           = NULL;
947*4882a593Smuzhiyun 	} else {
948*4882a593Smuzhiyun 		scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
949*4882a593Smuzhiyun 		SCpnt->SCp.buffer           = scsi_sglist(SCpnt);
950*4882a593Smuzhiyun 		SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
951*4882a593Smuzhiyun 		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
952*4882a593Smuzhiyun 	}
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun 	DO_LOCK(flags);
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun #if defined(AHA152X_STAT)
957*4882a593Smuzhiyun 	HOSTDATA(shpnt)->total_commands++;
958*4882a593Smuzhiyun #endif
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	/* Turn led on, when this is the first command. */
961*4882a593Smuzhiyun 	HOSTDATA(shpnt)->commands++;
962*4882a593Smuzhiyun 	if (HOSTDATA(shpnt)->commands==1)
963*4882a593Smuzhiyun 		SETPORT(PORTA, 1);
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	append_SC(&ISSUE_SC, SCpnt);
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	if(!HOSTDATA(shpnt)->in_intr)
968*4882a593Smuzhiyun 		setup_expected_interrupts(shpnt);
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	DO_UNLOCK(flags);
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	return 0;
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun /*
976*4882a593Smuzhiyun  *  queue a command
977*4882a593Smuzhiyun  *
978*4882a593Smuzhiyun  */
aha152x_queue_lck(struct scsi_cmnd * SCpnt,void (* done)(struct scsi_cmnd *))979*4882a593Smuzhiyun static int aha152x_queue_lck(struct scsi_cmnd *SCpnt,
980*4882a593Smuzhiyun 			     void (*done)(struct scsi_cmnd *))
981*4882a593Smuzhiyun {
982*4882a593Smuzhiyun 	return aha152x_internal_queue(SCpnt, NULL, 0, done);
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun 
DEF_SCSI_QCMD(aha152x_queue)985*4882a593Smuzhiyun static DEF_SCSI_QCMD(aha152x_queue)
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun /*
989*4882a593Smuzhiyun  *
990*4882a593Smuzhiyun  */
991*4882a593Smuzhiyun static void reset_done(struct scsi_cmnd *SCpnt)
992*4882a593Smuzhiyun {
993*4882a593Smuzhiyun 	if(SCSEM(SCpnt)) {
994*4882a593Smuzhiyun 		complete(SCSEM(SCpnt));
995*4882a593Smuzhiyun 	} else {
996*4882a593Smuzhiyun 		printk(KERN_ERR "aha152x: reset_done w/o completion\n");
997*4882a593Smuzhiyun 	}
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun /*
1001*4882a593Smuzhiyun  *  Abort a command
1002*4882a593Smuzhiyun  *
1003*4882a593Smuzhiyun  */
aha152x_abort(struct scsi_cmnd * SCpnt)1004*4882a593Smuzhiyun static int aha152x_abort(struct scsi_cmnd *SCpnt)
1005*4882a593Smuzhiyun {
1006*4882a593Smuzhiyun 	struct Scsi_Host *shpnt = SCpnt->device->host;
1007*4882a593Smuzhiyun 	struct scsi_cmnd *ptr;
1008*4882a593Smuzhiyun 	unsigned long flags;
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	DO_LOCK(flags);
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	ptr=remove_SC(&ISSUE_SC, SCpnt);
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	if(ptr) {
1015*4882a593Smuzhiyun 		HOSTDATA(shpnt)->commands--;
1016*4882a593Smuzhiyun 		if (!HOSTDATA(shpnt)->commands)
1017*4882a593Smuzhiyun 			SETPORT(PORTA, 0);
1018*4882a593Smuzhiyun 		DO_UNLOCK(flags);
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 		kfree(SCpnt->host_scribble);
1021*4882a593Smuzhiyun 		SCpnt->host_scribble=NULL;
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 		return SUCCESS;
1024*4882a593Smuzhiyun 	}
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	DO_UNLOCK(flags);
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	/*
1029*4882a593Smuzhiyun 	 * FIXME:
1030*4882a593Smuzhiyun 	 * for current command: queue ABORT for message out and raise ATN
1031*4882a593Smuzhiyun 	 * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
1032*4882a593Smuzhiyun 	 *
1033*4882a593Smuzhiyun 	 */
1034*4882a593Smuzhiyun 
1035*4882a593Smuzhiyun 	scmd_printk(KERN_ERR, SCpnt,
1036*4882a593Smuzhiyun 		    "cannot abort running or disconnected command\n");
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 	return FAILED;
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun /*
1042*4882a593Smuzhiyun  * Reset a device
1043*4882a593Smuzhiyun  *
1044*4882a593Smuzhiyun  */
aha152x_device_reset(struct scsi_cmnd * SCpnt)1045*4882a593Smuzhiyun static int aha152x_device_reset(struct scsi_cmnd * SCpnt)
1046*4882a593Smuzhiyun {
1047*4882a593Smuzhiyun 	struct Scsi_Host *shpnt = SCpnt->device->host;
1048*4882a593Smuzhiyun 	DECLARE_COMPLETION(done);
1049*4882a593Smuzhiyun 	int ret, issued, disconnected;
1050*4882a593Smuzhiyun 	unsigned char old_cmd_len = SCpnt->cmd_len;
1051*4882a593Smuzhiyun 	unsigned long flags;
1052*4882a593Smuzhiyun 	unsigned long timeleft;
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 	if(CURRENT_SC==SCpnt) {
1055*4882a593Smuzhiyun 		scmd_printk(KERN_ERR, SCpnt, "cannot reset current device\n");
1056*4882a593Smuzhiyun 		return FAILED;
1057*4882a593Smuzhiyun 	}
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun 	DO_LOCK(flags);
1060*4882a593Smuzhiyun 	issued       = remove_SC(&ISSUE_SC, SCpnt) == NULL;
1061*4882a593Smuzhiyun 	disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt);
1062*4882a593Smuzhiyun 	DO_UNLOCK(flags);
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 	SCpnt->cmd_len         = 0;
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun 	aha152x_internal_queue(SCpnt, &done, resetting, reset_done);
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	timeleft = wait_for_completion_timeout(&done, 100*HZ);
1069*4882a593Smuzhiyun 	if (!timeleft) {
1070*4882a593Smuzhiyun 		/* remove command from issue queue */
1071*4882a593Smuzhiyun 		DO_LOCK(flags);
1072*4882a593Smuzhiyun 		remove_SC(&ISSUE_SC, SCpnt);
1073*4882a593Smuzhiyun 		DO_UNLOCK(flags);
1074*4882a593Smuzhiyun 	}
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	SCpnt->cmd_len         = old_cmd_len;
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 	DO_LOCK(flags);
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 	if(SCpnt->SCp.phase & resetted) {
1081*4882a593Smuzhiyun 		HOSTDATA(shpnt)->commands--;
1082*4882a593Smuzhiyun 		if (!HOSTDATA(shpnt)->commands)
1083*4882a593Smuzhiyun 			SETPORT(PORTA, 0);
1084*4882a593Smuzhiyun 		kfree(SCpnt->host_scribble);
1085*4882a593Smuzhiyun 		SCpnt->host_scribble=NULL;
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun 		ret = SUCCESS;
1088*4882a593Smuzhiyun 	} else {
1089*4882a593Smuzhiyun 		/* requeue */
1090*4882a593Smuzhiyun 		if(!issued) {
1091*4882a593Smuzhiyun 			append_SC(&ISSUE_SC, SCpnt);
1092*4882a593Smuzhiyun 		} else if(disconnected) {
1093*4882a593Smuzhiyun 			append_SC(&DISCONNECTED_SC, SCpnt);
1094*4882a593Smuzhiyun 		}
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 		ret = FAILED;
1097*4882a593Smuzhiyun 	}
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun 	DO_UNLOCK(flags);
1100*4882a593Smuzhiyun 	return ret;
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun 
free_hard_reset_SCs(struct Scsi_Host * shpnt,struct scsi_cmnd ** SCs)1103*4882a593Smuzhiyun static void free_hard_reset_SCs(struct Scsi_Host *shpnt,
1104*4882a593Smuzhiyun 				struct scsi_cmnd **SCs)
1105*4882a593Smuzhiyun {
1106*4882a593Smuzhiyun 	struct scsi_cmnd *ptr;
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	ptr=*SCs;
1109*4882a593Smuzhiyun 	while(ptr) {
1110*4882a593Smuzhiyun 		struct scsi_cmnd *next;
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 		if(SCDATA(ptr)) {
1113*4882a593Smuzhiyun 			next = SCNEXT(ptr);
1114*4882a593Smuzhiyun 		} else {
1115*4882a593Smuzhiyun 			scmd_printk(KERN_DEBUG, ptr,
1116*4882a593Smuzhiyun 				    "queue corrupted at %p\n", ptr);
1117*4882a593Smuzhiyun 			next = NULL;
1118*4882a593Smuzhiyun 		}
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 		if (!ptr->device->soft_reset) {
1121*4882a593Smuzhiyun 			remove_SC(SCs, ptr);
1122*4882a593Smuzhiyun 			HOSTDATA(shpnt)->commands--;
1123*4882a593Smuzhiyun 			kfree(ptr->host_scribble);
1124*4882a593Smuzhiyun 			ptr->host_scribble=NULL;
1125*4882a593Smuzhiyun 		}
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 		ptr = next;
1128*4882a593Smuzhiyun 	}
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun /*
1132*4882a593Smuzhiyun  * Reset the bus
1133*4882a593Smuzhiyun  *
1134*4882a593Smuzhiyun  * AIC-6260 has a hard reset (MRST signal), but apparently
1135*4882a593Smuzhiyun  * one cannot trigger it via software. So live with
1136*4882a593Smuzhiyun  * a soft reset; no-one seemed to have cared.
1137*4882a593Smuzhiyun  */
aha152x_bus_reset_host(struct Scsi_Host * shpnt)1138*4882a593Smuzhiyun static int aha152x_bus_reset_host(struct Scsi_Host *shpnt)
1139*4882a593Smuzhiyun {
1140*4882a593Smuzhiyun 	unsigned long flags;
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	DO_LOCK(flags);
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun 	free_hard_reset_SCs(shpnt, &ISSUE_SC);
1145*4882a593Smuzhiyun 	free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun 	SETPORT(SCSISEQ, SCSIRSTO);
1148*4882a593Smuzhiyun 	mdelay(256);
1149*4882a593Smuzhiyun 	SETPORT(SCSISEQ, 0);
1150*4882a593Smuzhiyun 	mdelay(DELAY);
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun 	setup_expected_interrupts(shpnt);
1153*4882a593Smuzhiyun 	if(HOSTDATA(shpnt)->commands==0)
1154*4882a593Smuzhiyun 		SETPORT(PORTA, 0);
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	DO_UNLOCK(flags);
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	return SUCCESS;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun /*
1162*4882a593Smuzhiyun  * Reset the bus
1163*4882a593Smuzhiyun  *
1164*4882a593Smuzhiyun  */
aha152x_bus_reset(struct scsi_cmnd * SCpnt)1165*4882a593Smuzhiyun static int aha152x_bus_reset(struct scsi_cmnd *SCpnt)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun 	return aha152x_bus_reset_host(SCpnt->device->host);
1168*4882a593Smuzhiyun }
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun /*
1171*4882a593Smuzhiyun  *  Restore default values to the AIC-6260 registers and reset the fifos
1172*4882a593Smuzhiyun  *
1173*4882a593Smuzhiyun  */
reset_ports(struct Scsi_Host * shpnt)1174*4882a593Smuzhiyun static void reset_ports(struct Scsi_Host *shpnt)
1175*4882a593Smuzhiyun {
1176*4882a593Smuzhiyun 	unsigned long flags;
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	/* disable interrupts */
1179*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, RSTFIFO);
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 	SETPORT(SCSISEQ, 0);
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun 	SETPORT(SXFRCTL1, 0);
1184*4882a593Smuzhiyun 	SETPORT(SCSISIG, 0);
1185*4882a593Smuzhiyun 	SETRATE(0);
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 	/* clear all interrupt conditions */
1188*4882a593Smuzhiyun 	SETPORT(SSTAT0, 0x7f);
1189*4882a593Smuzhiyun 	SETPORT(SSTAT1, 0xef);
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	SETPORT(SSTAT4, SYNCERR | FWERR | FRERR);
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, 0);
1194*4882a593Smuzhiyun 	SETPORT(DMACNTRL1, 0);
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 	SETPORT(BRSTCNTRL, 0xf1);
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	/* clear SCSI fifos and transfer count */
1199*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
1200*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1);
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	DO_LOCK(flags);
1203*4882a593Smuzhiyun 	setup_expected_interrupts(shpnt);
1204*4882a593Smuzhiyun 	DO_UNLOCK(flags);
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun /*
1208*4882a593Smuzhiyun  * Reset the host (bus and controller)
1209*4882a593Smuzhiyun  *
1210*4882a593Smuzhiyun  */
aha152x_host_reset_host(struct Scsi_Host * shpnt)1211*4882a593Smuzhiyun int aha152x_host_reset_host(struct Scsi_Host *shpnt)
1212*4882a593Smuzhiyun {
1213*4882a593Smuzhiyun 	aha152x_bus_reset_host(shpnt);
1214*4882a593Smuzhiyun 	reset_ports(shpnt);
1215*4882a593Smuzhiyun 
1216*4882a593Smuzhiyun 	return SUCCESS;
1217*4882a593Smuzhiyun }
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun /*
1220*4882a593Smuzhiyun  * Return the "logical geometry"
1221*4882a593Smuzhiyun  *
1222*4882a593Smuzhiyun  */
aha152x_biosparam(struct scsi_device * sdev,struct block_device * bdev,sector_t capacity,int * info_array)1223*4882a593Smuzhiyun static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
1224*4882a593Smuzhiyun 		sector_t capacity, int *info_array)
1225*4882a593Smuzhiyun {
1226*4882a593Smuzhiyun 	struct Scsi_Host *shpnt = sdev->host;
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	/* try default translation */
1229*4882a593Smuzhiyun 	info_array[0] = 64;
1230*4882a593Smuzhiyun 	info_array[1] = 32;
1231*4882a593Smuzhiyun 	info_array[2] = (unsigned long)capacity / (64 * 32);
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 	/* for disks >1GB do some guessing */
1234*4882a593Smuzhiyun 	if (info_array[2] >= 1024) {
1235*4882a593Smuzhiyun 		int info[3];
1236*4882a593Smuzhiyun 
1237*4882a593Smuzhiyun 		/* try to figure out the geometry from the partition table */
1238*4882a593Smuzhiyun 		if (scsicam_bios_param(bdev, capacity, info) < 0 ||
1239*4882a593Smuzhiyun 		    !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
1240*4882a593Smuzhiyun 			if (EXT_TRANS) {
1241*4882a593Smuzhiyun 				printk(KERN_NOTICE
1242*4882a593Smuzhiyun 				       "aha152x: unable to verify geometry for disk with >1GB.\n"
1243*4882a593Smuzhiyun 				       "         using extended translation.\n");
1244*4882a593Smuzhiyun 				info_array[0] = 255;
1245*4882a593Smuzhiyun 				info_array[1] = 63;
1246*4882a593Smuzhiyun 				info_array[2] = (unsigned long)capacity / (255 * 63);
1247*4882a593Smuzhiyun 			} else {
1248*4882a593Smuzhiyun 				printk(KERN_NOTICE
1249*4882a593Smuzhiyun 				       "aha152x: unable to verify geometry for disk with >1GB.\n"
1250*4882a593Smuzhiyun 				       "         Using default translation. Please verify yourself.\n"
1251*4882a593Smuzhiyun 				       "         Perhaps you need to enable extended translation in the driver.\n"
1252*4882a593Smuzhiyun 				       "         See Documentation/scsi/aha152x.rst for details.\n");
1253*4882a593Smuzhiyun 			}
1254*4882a593Smuzhiyun 		} else {
1255*4882a593Smuzhiyun 			info_array[0] = info[0];
1256*4882a593Smuzhiyun 			info_array[1] = info[1];
1257*4882a593Smuzhiyun 			info_array[2] = info[2];
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 			if (info[0] == 255 && !EXT_TRANS) {
1260*4882a593Smuzhiyun 				printk(KERN_NOTICE
1261*4882a593Smuzhiyun 				       "aha152x: current partition table is using extended translation.\n"
1262*4882a593Smuzhiyun 				       "         using it also, although it's not explicitly enabled.\n");
1263*4882a593Smuzhiyun 			}
1264*4882a593Smuzhiyun 		}
1265*4882a593Smuzhiyun 	}
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 	return 0;
1268*4882a593Smuzhiyun }
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun /*
1271*4882a593Smuzhiyun  *  Internal done function
1272*4882a593Smuzhiyun  *
1273*4882a593Smuzhiyun  */
done(struct Scsi_Host * shpnt,int error)1274*4882a593Smuzhiyun static void done(struct Scsi_Host *shpnt, int error)
1275*4882a593Smuzhiyun {
1276*4882a593Smuzhiyun 	if (CURRENT_SC) {
1277*4882a593Smuzhiyun 		if(DONE_SC)
1278*4882a593Smuzhiyun 			scmd_printk(KERN_ERR, CURRENT_SC,
1279*4882a593Smuzhiyun 				    "there's already a completed command %p "
1280*4882a593Smuzhiyun 				    "- will cause abort\n", DONE_SC);
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 		DONE_SC = CURRENT_SC;
1283*4882a593Smuzhiyun 		CURRENT_SC = NULL;
1284*4882a593Smuzhiyun 		DONE_SC->result = error;
1285*4882a593Smuzhiyun 	} else
1286*4882a593Smuzhiyun 		printk(KERN_ERR "aha152x: done() called outside of command\n");
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun static struct work_struct aha152x_tq;
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun /*
1292*4882a593Smuzhiyun  * Run service completions on the card with interrupts enabled.
1293*4882a593Smuzhiyun  *
1294*4882a593Smuzhiyun  */
run(struct work_struct * work)1295*4882a593Smuzhiyun static void run(struct work_struct *work)
1296*4882a593Smuzhiyun {
1297*4882a593Smuzhiyun 	struct aha152x_hostdata *hd;
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 	list_for_each_entry(hd, &aha152x_host_list, host_list) {
1300*4882a593Smuzhiyun 		struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 		is_complete(shost);
1303*4882a593Smuzhiyun 	}
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun /*
1307*4882a593Smuzhiyun  * Interrupt handler
1308*4882a593Smuzhiyun  *
1309*4882a593Smuzhiyun  */
intr(int irqno,void * dev_id)1310*4882a593Smuzhiyun static irqreturn_t intr(int irqno, void *dev_id)
1311*4882a593Smuzhiyun {
1312*4882a593Smuzhiyun 	struct Scsi_Host *shpnt = dev_id;
1313*4882a593Smuzhiyun 	unsigned long flags;
1314*4882a593Smuzhiyun 	unsigned char rev, dmacntrl0;
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	/*
1317*4882a593Smuzhiyun 	 * Read a couple of registers that are known to not be all 1's. If
1318*4882a593Smuzhiyun 	 * we read all 1's (-1), that means that either:
1319*4882a593Smuzhiyun 	 *
1320*4882a593Smuzhiyun 	 * a. The host adapter chip has gone bad, and we cannot control it,
1321*4882a593Smuzhiyun 	 *	OR
1322*4882a593Smuzhiyun 	 * b. The host adapter is a PCMCIA card that has been ejected
1323*4882a593Smuzhiyun 	 *
1324*4882a593Smuzhiyun 	 * In either case, we cannot do anything with the host adapter at
1325*4882a593Smuzhiyun 	 * this point in time. So just ignore the interrupt and return.
1326*4882a593Smuzhiyun 	 * In the latter case, the interrupt might actually be meant for
1327*4882a593Smuzhiyun 	 * someone else sharing this IRQ, and that driver will handle it.
1328*4882a593Smuzhiyun 	 */
1329*4882a593Smuzhiyun 	rev = GETPORT(REV);
1330*4882a593Smuzhiyun 	dmacntrl0 = GETPORT(DMACNTRL0);
1331*4882a593Smuzhiyun 	if ((rev == 0xFF) && (dmacntrl0 == 0xFF))
1332*4882a593Smuzhiyun 		return IRQ_NONE;
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	if( TESTLO(DMASTAT, INTSTAT) )
1335*4882a593Smuzhiyun 		return IRQ_NONE;
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 	/* no more interrupts from the controller, while we're busy.
1338*4882a593Smuzhiyun 	   INTEN is restored by the BH handler */
1339*4882a593Smuzhiyun 	CLRBITS(DMACNTRL0, INTEN);
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun 	DO_LOCK(flags);
1342*4882a593Smuzhiyun 	if( HOSTDATA(shpnt)->service==0 ) {
1343*4882a593Smuzhiyun 		HOSTDATA(shpnt)->service=1;
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun 		/* Poke the BH handler */
1346*4882a593Smuzhiyun 		INIT_WORK(&aha152x_tq, run);
1347*4882a593Smuzhiyun 		schedule_work(&aha152x_tq);
1348*4882a593Smuzhiyun 	}
1349*4882a593Smuzhiyun 	DO_UNLOCK(flags);
1350*4882a593Smuzhiyun 
1351*4882a593Smuzhiyun 	return IRQ_HANDLED;
1352*4882a593Smuzhiyun }
1353*4882a593Smuzhiyun 
1354*4882a593Smuzhiyun /*
1355*4882a593Smuzhiyun  * busfree phase
1356*4882a593Smuzhiyun  * - handle completition/disconnection/error of current command
1357*4882a593Smuzhiyun  * - start selection for next command (if any)
1358*4882a593Smuzhiyun  */
busfree_run(struct Scsi_Host * shpnt)1359*4882a593Smuzhiyun static void busfree_run(struct Scsi_Host *shpnt)
1360*4882a593Smuzhiyun {
1361*4882a593Smuzhiyun 	unsigned long flags;
1362*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1363*4882a593Smuzhiyun 	int action=0;
1364*4882a593Smuzhiyun #endif
1365*4882a593Smuzhiyun 
1366*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
1367*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1);
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	SETPORT(SSTAT1, CLRBUSFREE);
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun 	if(CURRENT_SC) {
1372*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1373*4882a593Smuzhiyun 		action++;
1374*4882a593Smuzhiyun #endif
1375*4882a593Smuzhiyun 		CURRENT_SC->SCp.phase &= ~syncneg;
1376*4882a593Smuzhiyun 
1377*4882a593Smuzhiyun 		if(CURRENT_SC->SCp.phase & completed) {
1378*4882a593Smuzhiyun 			/* target sent COMMAND COMPLETE */
1379*4882a593Smuzhiyun 			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
1380*4882a593Smuzhiyun 
1381*4882a593Smuzhiyun 		} else if(CURRENT_SC->SCp.phase & aborted) {
1382*4882a593Smuzhiyun 			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16));
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 		} else if(CURRENT_SC->SCp.phase & resetted) {
1385*4882a593Smuzhiyun 			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16));
1386*4882a593Smuzhiyun 
1387*4882a593Smuzhiyun 		} else if(CURRENT_SC->SCp.phase & disconnected) {
1388*4882a593Smuzhiyun 			/* target sent DISCONNECT */
1389*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1390*4882a593Smuzhiyun 			HOSTDATA(shpnt)->disconnections++;
1391*4882a593Smuzhiyun #endif
1392*4882a593Smuzhiyun 			append_SC(&DISCONNECTED_SC, CURRENT_SC);
1393*4882a593Smuzhiyun 			CURRENT_SC->SCp.phase |= 1 << 16;
1394*4882a593Smuzhiyun 			CURRENT_SC = NULL;
1395*4882a593Smuzhiyun 
1396*4882a593Smuzhiyun 		} else {
1397*4882a593Smuzhiyun 			done(shpnt, DID_ERROR << 16);
1398*4882a593Smuzhiyun 		}
1399*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1400*4882a593Smuzhiyun 	} else {
1401*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_old_command++;
1402*4882a593Smuzhiyun #endif
1403*4882a593Smuzhiyun 	}
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun 	DO_LOCK(flags);
1406*4882a593Smuzhiyun 
1407*4882a593Smuzhiyun 	if(DONE_SC) {
1408*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1409*4882a593Smuzhiyun 		action++;
1410*4882a593Smuzhiyun #endif
1411*4882a593Smuzhiyun 
1412*4882a593Smuzhiyun 		if(DONE_SC->SCp.phase & check_condition) {
1413*4882a593Smuzhiyun 			struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
1414*4882a593Smuzhiyun 			struct aha152x_scdata *sc = SCDATA(cmd);
1415*4882a593Smuzhiyun 
1416*4882a593Smuzhiyun 			scsi_eh_restore_cmnd(cmd, &sc->ses);
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun 			cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
1419*4882a593Smuzhiyun 
1420*4882a593Smuzhiyun 			HOSTDATA(shpnt)->commands--;
1421*4882a593Smuzhiyun 			if (!HOSTDATA(shpnt)->commands)
1422*4882a593Smuzhiyun 				SETPORT(PORTA, 0);	/* turn led off */
1423*4882a593Smuzhiyun 		} else if(DONE_SC->SCp.Status==SAM_STAT_CHECK_CONDITION) {
1424*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1425*4882a593Smuzhiyun 			HOSTDATA(shpnt)->busfree_with_check_condition++;
1426*4882a593Smuzhiyun #endif
1427*4882a593Smuzhiyun 
1428*4882a593Smuzhiyun 			if(!(DONE_SC->SCp.phase & not_issued)) {
1429*4882a593Smuzhiyun 				struct aha152x_scdata *sc;
1430*4882a593Smuzhiyun 				struct scsi_cmnd *ptr = DONE_SC;
1431*4882a593Smuzhiyun 				DONE_SC=NULL;
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun 				sc = SCDATA(ptr);
1434*4882a593Smuzhiyun 				/* It was allocated in aha152x_internal_queue? */
1435*4882a593Smuzhiyun 				BUG_ON(!sc);
1436*4882a593Smuzhiyun 				scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 				DO_UNLOCK(flags);
1439*4882a593Smuzhiyun 				aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
1440*4882a593Smuzhiyun 				DO_LOCK(flags);
1441*4882a593Smuzhiyun 			}
1442*4882a593Smuzhiyun 		}
1443*4882a593Smuzhiyun 
1444*4882a593Smuzhiyun 		if(DONE_SC && DONE_SC->scsi_done) {
1445*4882a593Smuzhiyun 			struct scsi_cmnd *ptr = DONE_SC;
1446*4882a593Smuzhiyun 			DONE_SC=NULL;
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 			/* turn led off, when no commands are in the driver */
1449*4882a593Smuzhiyun 			HOSTDATA(shpnt)->commands--;
1450*4882a593Smuzhiyun 			if (!HOSTDATA(shpnt)->commands)
1451*4882a593Smuzhiyun 				SETPORT(PORTA, 0);	/* turn led off */
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun 			if(ptr->scsi_done != reset_done) {
1454*4882a593Smuzhiyun 				kfree(ptr->host_scribble);
1455*4882a593Smuzhiyun 				ptr->host_scribble=NULL;
1456*4882a593Smuzhiyun 			}
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 			DO_UNLOCK(flags);
1459*4882a593Smuzhiyun 			ptr->scsi_done(ptr);
1460*4882a593Smuzhiyun 			DO_LOCK(flags);
1461*4882a593Smuzhiyun 		}
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 		DONE_SC=NULL;
1464*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1465*4882a593Smuzhiyun 	} else {
1466*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_done_command++;
1467*4882a593Smuzhiyun #endif
1468*4882a593Smuzhiyun 	}
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun 	if(ISSUE_SC)
1471*4882a593Smuzhiyun 		CURRENT_SC = remove_first_SC(&ISSUE_SC);
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun 	DO_UNLOCK(flags);
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	if(CURRENT_SC) {
1476*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1477*4882a593Smuzhiyun 		action++;
1478*4882a593Smuzhiyun #endif
1479*4882a593Smuzhiyun 		CURRENT_SC->SCp.phase |= selecting;
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun 		/* clear selection timeout */
1482*4882a593Smuzhiyun 		SETPORT(SSTAT1, SELTO);
1483*4882a593Smuzhiyun 
1484*4882a593Smuzhiyun 		SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id);
1485*4882a593Smuzhiyun 		SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER);
1486*4882a593Smuzhiyun 		SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0));
1487*4882a593Smuzhiyun 	} else {
1488*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1489*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_new_command++;
1490*4882a593Smuzhiyun #endif
1491*4882a593Smuzhiyun 		SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
1492*4882a593Smuzhiyun 	}
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun #if defined(AHA152X_STAT)
1495*4882a593Smuzhiyun 	if(!action)
1496*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_any_action++;
1497*4882a593Smuzhiyun #endif
1498*4882a593Smuzhiyun }
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun /*
1501*4882a593Smuzhiyun  * Selection done (OUT)
1502*4882a593Smuzhiyun  * - queue IDENTIFY message and SDTR to selected target for message out
1503*4882a593Smuzhiyun  *   (ATN asserted automagically via ENAUTOATNO in busfree())
1504*4882a593Smuzhiyun  */
seldo_run(struct Scsi_Host * shpnt)1505*4882a593Smuzhiyun static void seldo_run(struct Scsi_Host *shpnt)
1506*4882a593Smuzhiyun {
1507*4882a593Smuzhiyun 	SETPORT(SCSISIG, 0);
1508*4882a593Smuzhiyun 	SETPORT(SSTAT1, CLRBUSFREE);
1509*4882a593Smuzhiyun 	SETPORT(SSTAT1, CLRPHASECHG);
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun 	SETPORT(SCSISEQ, 0);
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 	if (TESTLO(SSTAT0, SELDO)) {
1516*4882a593Smuzhiyun 		scmd_printk(KERN_ERR, CURRENT_SC,
1517*4882a593Smuzhiyun 			    "aha152x: passing bus free condition\n");
1518*4882a593Smuzhiyun 		done(shpnt, DID_NO_CONNECT << 16);
1519*4882a593Smuzhiyun 		return;
1520*4882a593Smuzhiyun 	}
1521*4882a593Smuzhiyun 
1522*4882a593Smuzhiyun 	SETPORT(SSTAT0, CLRSELDO);
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun 	ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
1525*4882a593Smuzhiyun 
1526*4882a593Smuzhiyun 	if (CURRENT_SC->SCp.phase & aborting) {
1527*4882a593Smuzhiyun 		ADDMSGO(ABORT);
1528*4882a593Smuzhiyun 	} else if (CURRENT_SC->SCp.phase & resetting) {
1529*4882a593Smuzhiyun 		ADDMSGO(BUS_DEVICE_RESET);
1530*4882a593Smuzhiyun 	} else if (SYNCNEG==0 && SYNCHRONOUS) {
1531*4882a593Smuzhiyun 		CURRENT_SC->SCp.phase |= syncneg;
1532*4882a593Smuzhiyun 		MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8);
1533*4882a593Smuzhiyun 		SYNCNEG=1;		/* negotiation in progress */
1534*4882a593Smuzhiyun 	}
1535*4882a593Smuzhiyun 
1536*4882a593Smuzhiyun 	SETRATE(SYNCRATE);
1537*4882a593Smuzhiyun }
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun /*
1540*4882a593Smuzhiyun  * Selection timeout
1541*4882a593Smuzhiyun  * - return command to mid-level with failure cause
1542*4882a593Smuzhiyun  *
1543*4882a593Smuzhiyun  */
selto_run(struct Scsi_Host * shpnt)1544*4882a593Smuzhiyun static void selto_run(struct Scsi_Host *shpnt)
1545*4882a593Smuzhiyun {
1546*4882a593Smuzhiyun 	SETPORT(SCSISEQ, 0);
1547*4882a593Smuzhiyun 	SETPORT(SSTAT1, CLRSELTIMO);
1548*4882a593Smuzhiyun 
1549*4882a593Smuzhiyun 	if (!CURRENT_SC)
1550*4882a593Smuzhiyun 		return;
1551*4882a593Smuzhiyun 
1552*4882a593Smuzhiyun 	CURRENT_SC->SCp.phase &= ~selecting;
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 	if (CURRENT_SC->SCp.phase & aborted)
1555*4882a593Smuzhiyun 		done(shpnt, DID_ABORT << 16);
1556*4882a593Smuzhiyun 	else if (TESTLO(SSTAT0, SELINGO))
1557*4882a593Smuzhiyun 		done(shpnt, DID_BUS_BUSY << 16);
1558*4882a593Smuzhiyun 	else
1559*4882a593Smuzhiyun 		/* ARBITRATION won, but SELECTION failed */
1560*4882a593Smuzhiyun 		done(shpnt, DID_NO_CONNECT << 16);
1561*4882a593Smuzhiyun }
1562*4882a593Smuzhiyun 
1563*4882a593Smuzhiyun /*
1564*4882a593Smuzhiyun  * Selection in done
1565*4882a593Smuzhiyun  * - put current command back to issue queue
1566*4882a593Smuzhiyun  *   (reconnection of a disconnected nexus instead
1567*4882a593Smuzhiyun  *    of successful selection out)
1568*4882a593Smuzhiyun  *
1569*4882a593Smuzhiyun  */
seldi_run(struct Scsi_Host * shpnt)1570*4882a593Smuzhiyun static void seldi_run(struct Scsi_Host *shpnt)
1571*4882a593Smuzhiyun {
1572*4882a593Smuzhiyun 	int selid;
1573*4882a593Smuzhiyun 	int target;
1574*4882a593Smuzhiyun 	unsigned long flags;
1575*4882a593Smuzhiyun 
1576*4882a593Smuzhiyun 	SETPORT(SCSISIG, 0);
1577*4882a593Smuzhiyun 	SETPORT(SSTAT0, CLRSELDI);
1578*4882a593Smuzhiyun 	SETPORT(SSTAT1, CLRBUSFREE);
1579*4882a593Smuzhiyun 	SETPORT(SSTAT1, CLRPHASECHG);
1580*4882a593Smuzhiyun 
1581*4882a593Smuzhiyun 	if(CURRENT_SC) {
1582*4882a593Smuzhiyun 		if(!(CURRENT_SC->SCp.phase & not_issued))
1583*4882a593Smuzhiyun 			scmd_printk(KERN_ERR, CURRENT_SC,
1584*4882a593Smuzhiyun 				    "command should not have been issued yet\n");
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 		DO_LOCK(flags);
1587*4882a593Smuzhiyun 		append_SC(&ISSUE_SC, CURRENT_SC);
1588*4882a593Smuzhiyun 		DO_UNLOCK(flags);
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun 		CURRENT_SC = NULL;
1591*4882a593Smuzhiyun 	}
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 	if (!DISCONNECTED_SC)
1594*4882a593Smuzhiyun 		return;
1595*4882a593Smuzhiyun 
1596*4882a593Smuzhiyun 	RECONN_TARGET=-1;
1597*4882a593Smuzhiyun 
1598*4882a593Smuzhiyun 	selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
1599*4882a593Smuzhiyun 
1600*4882a593Smuzhiyun 	if (selid==0) {
1601*4882a593Smuzhiyun 		shost_printk(KERN_INFO, shpnt,
1602*4882a593Smuzhiyun 			     "target id unknown (%02x)\n", selid);
1603*4882a593Smuzhiyun 		return;
1604*4882a593Smuzhiyun 	}
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun 	for(target=7; !(selid & (1 << target)); target--)
1607*4882a593Smuzhiyun 		;
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun 	if(selid & ~(1 << target)) {
1610*4882a593Smuzhiyun 		shost_printk(KERN_INFO, shpnt,
1611*4882a593Smuzhiyun 			     "multiple targets reconnected (%02x)\n", selid);
1612*4882a593Smuzhiyun 	}
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun 	SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
1616*4882a593Smuzhiyun 	SETPORT(SCSISEQ, 0);
1617*4882a593Smuzhiyun 
1618*4882a593Smuzhiyun 	SETRATE(HOSTDATA(shpnt)->syncrate[target]);
1619*4882a593Smuzhiyun 
1620*4882a593Smuzhiyun 	RECONN_TARGET=target;
1621*4882a593Smuzhiyun }
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun /*
1624*4882a593Smuzhiyun  * message in phase
1625*4882a593Smuzhiyun  * - handle initial message after reconnection to identify
1626*4882a593Smuzhiyun  *   reconnecting nexus
1627*4882a593Smuzhiyun  * - queue command on DISCONNECTED_SC on DISCONNECT message
1628*4882a593Smuzhiyun  * - set completed flag on COMMAND COMPLETE
1629*4882a593Smuzhiyun  *   (other completition code moved to busfree_run)
1630*4882a593Smuzhiyun  * - handle response to SDTR
1631*4882a593Smuzhiyun  * - clear synchronous transfer agreements on BUS RESET
1632*4882a593Smuzhiyun  *
1633*4882a593Smuzhiyun  * FIXME: what about SAVE POINTERS, RESTORE POINTERS?
1634*4882a593Smuzhiyun  *
1635*4882a593Smuzhiyun  */
msgi_run(struct Scsi_Host * shpnt)1636*4882a593Smuzhiyun static void msgi_run(struct Scsi_Host *shpnt)
1637*4882a593Smuzhiyun {
1638*4882a593Smuzhiyun 	for(;;) {
1639*4882a593Smuzhiyun 		int sstat1 = GETPORT(SSTAT1);
1640*4882a593Smuzhiyun 
1641*4882a593Smuzhiyun 		if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
1642*4882a593Smuzhiyun 			return;
1643*4882a593Smuzhiyun 
1644*4882a593Smuzhiyun 		if (TESTLO(SSTAT0, SPIORDY))
1645*4882a593Smuzhiyun 			return;
1646*4882a593Smuzhiyun 
1647*4882a593Smuzhiyun 		ADDMSGI(GETPORT(SCSIDAT));
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun 		if(!CURRENT_SC) {
1650*4882a593Smuzhiyun 			if(LASTSTATE!=seldi) {
1651*4882a593Smuzhiyun 				shost_printk(KERN_ERR, shpnt,
1652*4882a593Smuzhiyun 					     "message in w/o current command"
1653*4882a593Smuzhiyun 					     " not after reselection\n");
1654*4882a593Smuzhiyun 			}
1655*4882a593Smuzhiyun 
1656*4882a593Smuzhiyun 			/*
1657*4882a593Smuzhiyun 			 * Handle reselection
1658*4882a593Smuzhiyun 			 */
1659*4882a593Smuzhiyun 			if(!(MSGI(0) & IDENTIFY_BASE)) {
1660*4882a593Smuzhiyun 				shost_printk(KERN_ERR, shpnt,
1661*4882a593Smuzhiyun 					     "target didn't identify after reselection\n");
1662*4882a593Smuzhiyun 				continue;
1663*4882a593Smuzhiyun 			}
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun 			CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
1666*4882a593Smuzhiyun 
1667*4882a593Smuzhiyun 			if (!CURRENT_SC) {
1668*4882a593Smuzhiyun 				show_queues(shpnt);
1669*4882a593Smuzhiyun 				shost_printk(KERN_ERR, shpnt,
1670*4882a593Smuzhiyun 					     "no disconnected command"
1671*4882a593Smuzhiyun 					     " for target %d/%d\n",
1672*4882a593Smuzhiyun 					     RECONN_TARGET, MSGI(0) & 0x3f);
1673*4882a593Smuzhiyun 				continue;
1674*4882a593Smuzhiyun 			}
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 			CURRENT_SC->SCp.Message = MSGI(0);
1677*4882a593Smuzhiyun 			CURRENT_SC->SCp.phase &= ~disconnected;
1678*4882a593Smuzhiyun 
1679*4882a593Smuzhiyun 			MSGILEN=0;
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 			/* next message if any */
1682*4882a593Smuzhiyun 			continue;
1683*4882a593Smuzhiyun 		}
1684*4882a593Smuzhiyun 
1685*4882a593Smuzhiyun 		CURRENT_SC->SCp.Message = MSGI(0);
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 		switch (MSGI(0)) {
1688*4882a593Smuzhiyun 		case DISCONNECT:
1689*4882a593Smuzhiyun 			if (!RECONNECT)
1690*4882a593Smuzhiyun 				scmd_printk(KERN_WARNING, CURRENT_SC,
1691*4882a593Smuzhiyun 					    "target was not allowed to disconnect\n");
1692*4882a593Smuzhiyun 
1693*4882a593Smuzhiyun 			CURRENT_SC->SCp.phase |= disconnected;
1694*4882a593Smuzhiyun 			break;
1695*4882a593Smuzhiyun 
1696*4882a593Smuzhiyun 		case COMMAND_COMPLETE:
1697*4882a593Smuzhiyun 			CURRENT_SC->SCp.phase |= completed;
1698*4882a593Smuzhiyun 			break;
1699*4882a593Smuzhiyun 
1700*4882a593Smuzhiyun 		case MESSAGE_REJECT:
1701*4882a593Smuzhiyun 			if (SYNCNEG==1) {
1702*4882a593Smuzhiyun 				scmd_printk(KERN_INFO, CURRENT_SC,
1703*4882a593Smuzhiyun 					    "Synchronous Data Transfer Request"
1704*4882a593Smuzhiyun 					    " was rejected\n");
1705*4882a593Smuzhiyun 				SYNCNEG=2;	/* negotiation completed */
1706*4882a593Smuzhiyun 			} else
1707*4882a593Smuzhiyun 				scmd_printk(KERN_INFO, CURRENT_SC,
1708*4882a593Smuzhiyun 					    "inbound message (MESSAGE REJECT)\n");
1709*4882a593Smuzhiyun 			break;
1710*4882a593Smuzhiyun 
1711*4882a593Smuzhiyun 		case SAVE_POINTERS:
1712*4882a593Smuzhiyun 			break;
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun 		case RESTORE_POINTERS:
1715*4882a593Smuzhiyun 			break;
1716*4882a593Smuzhiyun 
1717*4882a593Smuzhiyun 		case EXTENDED_MESSAGE:
1718*4882a593Smuzhiyun 			if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
1719*4882a593Smuzhiyun 				/* not yet completed */
1720*4882a593Smuzhiyun 				continue;
1721*4882a593Smuzhiyun 			}
1722*4882a593Smuzhiyun 
1723*4882a593Smuzhiyun 			switch (MSGI(2)) {
1724*4882a593Smuzhiyun 			case EXTENDED_SDTR:
1725*4882a593Smuzhiyun 				{
1726*4882a593Smuzhiyun 					long ticks;
1727*4882a593Smuzhiyun 
1728*4882a593Smuzhiyun 					if (MSGI(1) != 3) {
1729*4882a593Smuzhiyun 						scmd_printk(KERN_ERR, CURRENT_SC,
1730*4882a593Smuzhiyun 							    "SDTR message length!=3\n");
1731*4882a593Smuzhiyun 						break;
1732*4882a593Smuzhiyun 					}
1733*4882a593Smuzhiyun 
1734*4882a593Smuzhiyun 					if (!HOSTDATA(shpnt)->synchronous)
1735*4882a593Smuzhiyun 						break;
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun 					printk(INFO_LEAD, CMDINFO(CURRENT_SC));
1738*4882a593Smuzhiyun 					spi_print_msg(&MSGI(0));
1739*4882a593Smuzhiyun 					printk("\n");
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun 					ticks = (MSGI(3) * 4 + 49) / 50;
1742*4882a593Smuzhiyun 
1743*4882a593Smuzhiyun 					if (syncneg) {
1744*4882a593Smuzhiyun 						/* negotiation in progress */
1745*4882a593Smuzhiyun 						if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
1746*4882a593Smuzhiyun 							ADDMSGO(MESSAGE_REJECT);
1747*4882a593Smuzhiyun 							scmd_printk(KERN_INFO,
1748*4882a593Smuzhiyun 								    CURRENT_SC,
1749*4882a593Smuzhiyun 								    "received Synchronous Data Transfer Request invalid - rejected\n");
1750*4882a593Smuzhiyun 							break;
1751*4882a593Smuzhiyun 						}
1752*4882a593Smuzhiyun 
1753*4882a593Smuzhiyun 						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
1754*4882a593Smuzhiyun 					} else if (ticks <= 9 && MSGI(4) >= 1) {
1755*4882a593Smuzhiyun 						ADDMSGO(EXTENDED_MESSAGE);
1756*4882a593Smuzhiyun 						ADDMSGO(3);
1757*4882a593Smuzhiyun 						ADDMSGO(EXTENDED_SDTR);
1758*4882a593Smuzhiyun 						if (ticks < 4) {
1759*4882a593Smuzhiyun 							ticks = 4;
1760*4882a593Smuzhiyun 							ADDMSGO(50);
1761*4882a593Smuzhiyun 						} else
1762*4882a593Smuzhiyun 							ADDMSGO(MSGI(3));
1763*4882a593Smuzhiyun 
1764*4882a593Smuzhiyun 						if (MSGI(4) > 8)
1765*4882a593Smuzhiyun 							MSGI(4) = 8;
1766*4882a593Smuzhiyun 
1767*4882a593Smuzhiyun 						ADDMSGO(MSGI(4));
1768*4882a593Smuzhiyun 
1769*4882a593Smuzhiyun 						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
1770*4882a593Smuzhiyun 					} else {
1771*4882a593Smuzhiyun 						/* requested SDTR is too slow, do it asynchronously */
1772*4882a593Smuzhiyun 						scmd_printk(KERN_INFO,
1773*4882a593Smuzhiyun 							    CURRENT_SC,
1774*4882a593Smuzhiyun 							    "Synchronous Data Transfer Request too slow - Rejecting\n");
1775*4882a593Smuzhiyun 						ADDMSGO(MESSAGE_REJECT);
1776*4882a593Smuzhiyun 					}
1777*4882a593Smuzhiyun 
1778*4882a593Smuzhiyun 					/* negotiation completed */
1779*4882a593Smuzhiyun 					SYNCNEG=2;
1780*4882a593Smuzhiyun 					SETRATE(SYNCRATE);
1781*4882a593Smuzhiyun 				}
1782*4882a593Smuzhiyun 				break;
1783*4882a593Smuzhiyun 
1784*4882a593Smuzhiyun 			case BUS_DEVICE_RESET:
1785*4882a593Smuzhiyun 				{
1786*4882a593Smuzhiyun 					int i;
1787*4882a593Smuzhiyun 
1788*4882a593Smuzhiyun 					for(i=0; i<8; i++) {
1789*4882a593Smuzhiyun 						HOSTDATA(shpnt)->syncrate[i]=0;
1790*4882a593Smuzhiyun 						HOSTDATA(shpnt)->syncneg[i]=0;
1791*4882a593Smuzhiyun 					}
1792*4882a593Smuzhiyun 
1793*4882a593Smuzhiyun 				}
1794*4882a593Smuzhiyun 				break;
1795*4882a593Smuzhiyun 
1796*4882a593Smuzhiyun 			case EXTENDED_MODIFY_DATA_POINTER:
1797*4882a593Smuzhiyun 			case EXTENDED_EXTENDED_IDENTIFY:
1798*4882a593Smuzhiyun 			case EXTENDED_WDTR:
1799*4882a593Smuzhiyun 			default:
1800*4882a593Smuzhiyun 				ADDMSGO(MESSAGE_REJECT);
1801*4882a593Smuzhiyun 				break;
1802*4882a593Smuzhiyun 			}
1803*4882a593Smuzhiyun 			break;
1804*4882a593Smuzhiyun 		}
1805*4882a593Smuzhiyun 
1806*4882a593Smuzhiyun 		MSGILEN=0;
1807*4882a593Smuzhiyun 	}
1808*4882a593Smuzhiyun }
1809*4882a593Smuzhiyun 
msgi_end(struct Scsi_Host * shpnt)1810*4882a593Smuzhiyun static void msgi_end(struct Scsi_Host *shpnt)
1811*4882a593Smuzhiyun {
1812*4882a593Smuzhiyun 	if(MSGILEN>0)
1813*4882a593Smuzhiyun 		scmd_printk(KERN_WARNING, CURRENT_SC,
1814*4882a593Smuzhiyun 			    "target left before message completed (%d)\n",
1815*4882a593Smuzhiyun 			    MSGILEN);
1816*4882a593Smuzhiyun 
1817*4882a593Smuzhiyun 	if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE))
1818*4882a593Smuzhiyun 		SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
1819*4882a593Smuzhiyun }
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun /*
1822*4882a593Smuzhiyun  * message out phase
1823*4882a593Smuzhiyun  *
1824*4882a593Smuzhiyun  */
msgo_init(struct Scsi_Host * shpnt)1825*4882a593Smuzhiyun static void msgo_init(struct Scsi_Host *shpnt)
1826*4882a593Smuzhiyun {
1827*4882a593Smuzhiyun 	if(MSGOLEN==0) {
1828*4882a593Smuzhiyun 		if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) {
1829*4882a593Smuzhiyun 			ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
1830*4882a593Smuzhiyun 		} else {
1831*4882a593Smuzhiyun 			scmd_printk(KERN_INFO, CURRENT_SC,
1832*4882a593Smuzhiyun 				    "unexpected MESSAGE OUT phase; rejecting\n");
1833*4882a593Smuzhiyun 			ADDMSGO(MESSAGE_REJECT);
1834*4882a593Smuzhiyun 		}
1835*4882a593Smuzhiyun 	}
1836*4882a593Smuzhiyun 
1837*4882a593Smuzhiyun }
1838*4882a593Smuzhiyun 
1839*4882a593Smuzhiyun /*
1840*4882a593Smuzhiyun  * message out phase
1841*4882a593Smuzhiyun  *
1842*4882a593Smuzhiyun  */
msgo_run(struct Scsi_Host * shpnt)1843*4882a593Smuzhiyun static void msgo_run(struct Scsi_Host *shpnt)
1844*4882a593Smuzhiyun {
1845*4882a593Smuzhiyun 	while(MSGO_I<MSGOLEN) {
1846*4882a593Smuzhiyun 		if (TESTLO(SSTAT0, SPIORDY))
1847*4882a593Smuzhiyun 			return;
1848*4882a593Smuzhiyun 
1849*4882a593Smuzhiyun 		if (MSGO_I==MSGOLEN-1) {
1850*4882a593Smuzhiyun 			/* Leave MESSAGE OUT after transfer */
1851*4882a593Smuzhiyun 			SETPORT(SSTAT1, CLRATNO);
1852*4882a593Smuzhiyun 		}
1853*4882a593Smuzhiyun 
1854*4882a593Smuzhiyun 
1855*4882a593Smuzhiyun 		if (MSGO(MSGO_I) & IDENTIFY_BASE)
1856*4882a593Smuzhiyun 			CURRENT_SC->SCp.phase |= identified;
1857*4882a593Smuzhiyun 
1858*4882a593Smuzhiyun 		if (MSGO(MSGO_I)==ABORT)
1859*4882a593Smuzhiyun 			CURRENT_SC->SCp.phase |= aborted;
1860*4882a593Smuzhiyun 
1861*4882a593Smuzhiyun 		if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
1862*4882a593Smuzhiyun 			CURRENT_SC->SCp.phase |= resetted;
1863*4882a593Smuzhiyun 
1864*4882a593Smuzhiyun 		SETPORT(SCSIDAT, MSGO(MSGO_I++));
1865*4882a593Smuzhiyun 	}
1866*4882a593Smuzhiyun }
1867*4882a593Smuzhiyun 
msgo_end(struct Scsi_Host * shpnt)1868*4882a593Smuzhiyun static void msgo_end(struct Scsi_Host *shpnt)
1869*4882a593Smuzhiyun {
1870*4882a593Smuzhiyun 	if(MSGO_I<MSGOLEN) {
1871*4882a593Smuzhiyun 		scmd_printk(KERN_ERR, CURRENT_SC,
1872*4882a593Smuzhiyun 			    "message sent incompletely (%d/%d)\n",
1873*4882a593Smuzhiyun 			    MSGO_I, MSGOLEN);
1874*4882a593Smuzhiyun 		if(SYNCNEG==1) {
1875*4882a593Smuzhiyun 			scmd_printk(KERN_INFO, CURRENT_SC,
1876*4882a593Smuzhiyun 				    "Synchronous Data Transfer Request was rejected\n");
1877*4882a593Smuzhiyun 			SYNCNEG=2;
1878*4882a593Smuzhiyun 		}
1879*4882a593Smuzhiyun 	}
1880*4882a593Smuzhiyun 
1881*4882a593Smuzhiyun 	MSGO_I  = 0;
1882*4882a593Smuzhiyun 	MSGOLEN = 0;
1883*4882a593Smuzhiyun }
1884*4882a593Smuzhiyun 
1885*4882a593Smuzhiyun /*
1886*4882a593Smuzhiyun  * command phase
1887*4882a593Smuzhiyun  *
1888*4882a593Smuzhiyun  */
cmd_init(struct Scsi_Host * shpnt)1889*4882a593Smuzhiyun static void cmd_init(struct Scsi_Host *shpnt)
1890*4882a593Smuzhiyun {
1891*4882a593Smuzhiyun 	if (CURRENT_SC->SCp.sent_command) {
1892*4882a593Smuzhiyun 		scmd_printk(KERN_ERR, CURRENT_SC,
1893*4882a593Smuzhiyun 			    "command already sent\n");
1894*4882a593Smuzhiyun 		done(shpnt, DID_ERROR << 16);
1895*4882a593Smuzhiyun 		return;
1896*4882a593Smuzhiyun 	}
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun 	CMD_I=0;
1899*4882a593Smuzhiyun }
1900*4882a593Smuzhiyun 
1901*4882a593Smuzhiyun /*
1902*4882a593Smuzhiyun  * command phase
1903*4882a593Smuzhiyun  *
1904*4882a593Smuzhiyun  */
cmd_run(struct Scsi_Host * shpnt)1905*4882a593Smuzhiyun static void cmd_run(struct Scsi_Host *shpnt)
1906*4882a593Smuzhiyun {
1907*4882a593Smuzhiyun 	while(CMD_I<CURRENT_SC->cmd_len) {
1908*4882a593Smuzhiyun 		if (TESTLO(SSTAT0, SPIORDY))
1909*4882a593Smuzhiyun 			return;
1910*4882a593Smuzhiyun 
1911*4882a593Smuzhiyun 		SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
1912*4882a593Smuzhiyun 	}
1913*4882a593Smuzhiyun }
1914*4882a593Smuzhiyun 
cmd_end(struct Scsi_Host * shpnt)1915*4882a593Smuzhiyun static void cmd_end(struct Scsi_Host *shpnt)
1916*4882a593Smuzhiyun {
1917*4882a593Smuzhiyun 	if(CMD_I<CURRENT_SC->cmd_len)
1918*4882a593Smuzhiyun 		scmd_printk(KERN_ERR, CURRENT_SC,
1919*4882a593Smuzhiyun 			    "command sent incompletely (%d/%d)\n",
1920*4882a593Smuzhiyun 			    CMD_I, CURRENT_SC->cmd_len);
1921*4882a593Smuzhiyun 	else
1922*4882a593Smuzhiyun 		CURRENT_SC->SCp.sent_command++;
1923*4882a593Smuzhiyun }
1924*4882a593Smuzhiyun 
1925*4882a593Smuzhiyun /*
1926*4882a593Smuzhiyun  * status phase
1927*4882a593Smuzhiyun  *
1928*4882a593Smuzhiyun  */
status_run(struct Scsi_Host * shpnt)1929*4882a593Smuzhiyun static void status_run(struct Scsi_Host *shpnt)
1930*4882a593Smuzhiyun {
1931*4882a593Smuzhiyun 	if (TESTLO(SSTAT0, SPIORDY))
1932*4882a593Smuzhiyun 		return;
1933*4882a593Smuzhiyun 
1934*4882a593Smuzhiyun 	CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
1935*4882a593Smuzhiyun 
1936*4882a593Smuzhiyun }
1937*4882a593Smuzhiyun 
1938*4882a593Smuzhiyun /*
1939*4882a593Smuzhiyun  * data in phase
1940*4882a593Smuzhiyun  *
1941*4882a593Smuzhiyun  */
datai_init(struct Scsi_Host * shpnt)1942*4882a593Smuzhiyun static void datai_init(struct Scsi_Host *shpnt)
1943*4882a593Smuzhiyun {
1944*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, RSTFIFO);
1945*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
1946*4882a593Smuzhiyun 
1947*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
1948*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
1949*4882a593Smuzhiyun 
1950*4882a593Smuzhiyun 	SETPORT(SIMODE0, 0);
1951*4882a593Smuzhiyun 	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
1952*4882a593Smuzhiyun 
1953*4882a593Smuzhiyun 	DATA_LEN=0;
1954*4882a593Smuzhiyun }
1955*4882a593Smuzhiyun 
datai_run(struct Scsi_Host * shpnt)1956*4882a593Smuzhiyun static void datai_run(struct Scsi_Host *shpnt)
1957*4882a593Smuzhiyun {
1958*4882a593Smuzhiyun 	unsigned long the_time;
1959*4882a593Smuzhiyun 	int fifodata, data_count;
1960*4882a593Smuzhiyun 
1961*4882a593Smuzhiyun 	/*
1962*4882a593Smuzhiyun 	 * loop while the phase persists or the fifos are not empty
1963*4882a593Smuzhiyun 	 *
1964*4882a593Smuzhiyun 	 */
1965*4882a593Smuzhiyun 	while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) {
1966*4882a593Smuzhiyun 		/* FIXME: maybe this should be done by setting up
1967*4882a593Smuzhiyun 		 * STCNT to trigger ENSWRAP interrupt, instead of
1968*4882a593Smuzhiyun 		 * polling for DFIFOFULL
1969*4882a593Smuzhiyun 		 */
1970*4882a593Smuzhiyun 		the_time=jiffies + 100*HZ;
1971*4882a593Smuzhiyun 		while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
1972*4882a593Smuzhiyun 			barrier();
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun 		if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
1975*4882a593Smuzhiyun 			scmd_printk(KERN_ERR, CURRENT_SC, "datai timeout\n");
1976*4882a593Smuzhiyun 			break;
1977*4882a593Smuzhiyun 		}
1978*4882a593Smuzhiyun 
1979*4882a593Smuzhiyun 		if(TESTHI(DMASTAT, DFIFOFULL)) {
1980*4882a593Smuzhiyun 			fifodata = 128;
1981*4882a593Smuzhiyun 		} else {
1982*4882a593Smuzhiyun 			the_time=jiffies + 100*HZ;
1983*4882a593Smuzhiyun 			while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
1984*4882a593Smuzhiyun 				barrier();
1985*4882a593Smuzhiyun 
1986*4882a593Smuzhiyun 			if(TESTLO(SSTAT2, SEMPTY)) {
1987*4882a593Smuzhiyun 				scmd_printk(KERN_ERR, CURRENT_SC,
1988*4882a593Smuzhiyun 					    "datai sempty timeout");
1989*4882a593Smuzhiyun 				break;
1990*4882a593Smuzhiyun 			}
1991*4882a593Smuzhiyun 
1992*4882a593Smuzhiyun 			fifodata = GETPORT(FIFOSTAT);
1993*4882a593Smuzhiyun 		}
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun 		if(CURRENT_SC->SCp.this_residual>0) {
1996*4882a593Smuzhiyun 			while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
1997*4882a593Smuzhiyun 				data_count = fifodata > CURRENT_SC->SCp.this_residual ?
1998*4882a593Smuzhiyun 						CURRENT_SC->SCp.this_residual :
1999*4882a593Smuzhiyun 						fifodata;
2000*4882a593Smuzhiyun 				fifodata -= data_count;
2001*4882a593Smuzhiyun 
2002*4882a593Smuzhiyun 				if (data_count & 1) {
2003*4882a593Smuzhiyun 					SETPORT(DMACNTRL0, ENDMA|_8BIT);
2004*4882a593Smuzhiyun 					*CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
2005*4882a593Smuzhiyun 					CURRENT_SC->SCp.this_residual--;
2006*4882a593Smuzhiyun 					DATA_LEN++;
2007*4882a593Smuzhiyun 					SETPORT(DMACNTRL0, ENDMA);
2008*4882a593Smuzhiyun 				}
2009*4882a593Smuzhiyun 
2010*4882a593Smuzhiyun 				if (data_count > 1) {
2011*4882a593Smuzhiyun 					data_count >>= 1;
2012*4882a593Smuzhiyun 					insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
2013*4882a593Smuzhiyun 					CURRENT_SC->SCp.ptr += 2 * data_count;
2014*4882a593Smuzhiyun 					CURRENT_SC->SCp.this_residual -= 2 * data_count;
2015*4882a593Smuzhiyun 					DATA_LEN += 2 * data_count;
2016*4882a593Smuzhiyun 				}
2017*4882a593Smuzhiyun 
2018*4882a593Smuzhiyun 				if (CURRENT_SC->SCp.this_residual == 0 &&
2019*4882a593Smuzhiyun 				    !sg_is_last(CURRENT_SC->SCp.buffer)) {
2020*4882a593Smuzhiyun 					/* advance to next buffer */
2021*4882a593Smuzhiyun 					CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
2022*4882a593Smuzhiyun 					CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
2023*4882a593Smuzhiyun 					CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
2024*4882a593Smuzhiyun 				}
2025*4882a593Smuzhiyun 			}
2026*4882a593Smuzhiyun 		} else if (fifodata > 0) {
2027*4882a593Smuzhiyun 			scmd_printk(KERN_ERR, CURRENT_SC,
2028*4882a593Smuzhiyun 				    "no buffers left for %d(%d) bytes"
2029*4882a593Smuzhiyun 				    " (data overrun!?)\n",
2030*4882a593Smuzhiyun 				    fifodata, GETPORT(FIFOSTAT));
2031*4882a593Smuzhiyun 			SETPORT(DMACNTRL0, ENDMA|_8BIT);
2032*4882a593Smuzhiyun 			while(fifodata>0) {
2033*4882a593Smuzhiyun 				GETPORT(DATAPORT);
2034*4882a593Smuzhiyun 				fifodata--;
2035*4882a593Smuzhiyun 				DATA_LEN++;
2036*4882a593Smuzhiyun 			}
2037*4882a593Smuzhiyun 			SETPORT(DMACNTRL0, ENDMA|_8BIT);
2038*4882a593Smuzhiyun 		}
2039*4882a593Smuzhiyun 	}
2040*4882a593Smuzhiyun 
2041*4882a593Smuzhiyun 	if(TESTLO(DMASTAT, INTSTAT) ||
2042*4882a593Smuzhiyun 	   TESTLO(DMASTAT, DFIFOEMP) ||
2043*4882a593Smuzhiyun 	   TESTLO(SSTAT2, SEMPTY) ||
2044*4882a593Smuzhiyun 	   GETPORT(FIFOSTAT)>0) {
2045*4882a593Smuzhiyun 		/*
2046*4882a593Smuzhiyun 		 * something went wrong, if there's something left in the fifos
2047*4882a593Smuzhiyun 		 * or the phase didn't change
2048*4882a593Smuzhiyun 		 */
2049*4882a593Smuzhiyun 		scmd_printk(KERN_ERR, CURRENT_SC,
2050*4882a593Smuzhiyun 			    "fifos should be empty and phase should have changed\n");
2051*4882a593Smuzhiyun 	}
2052*4882a593Smuzhiyun 
2053*4882a593Smuzhiyun 	if(DATA_LEN!=GETSTCNT()) {
2054*4882a593Smuzhiyun 		scmd_printk(KERN_ERR, CURRENT_SC,
2055*4882a593Smuzhiyun 			    "manual transfer count differs from automatic "
2056*4882a593Smuzhiyun 			    "(count=%d;stcnt=%d;diff=%d;fifostat=%d)",
2057*4882a593Smuzhiyun 			    DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN,
2058*4882a593Smuzhiyun 			    GETPORT(FIFOSTAT));
2059*4882a593Smuzhiyun 		mdelay(10000);
2060*4882a593Smuzhiyun 	}
2061*4882a593Smuzhiyun }
2062*4882a593Smuzhiyun 
datai_end(struct Scsi_Host * shpnt)2063*4882a593Smuzhiyun static void datai_end(struct Scsi_Host *shpnt)
2064*4882a593Smuzhiyun {
2065*4882a593Smuzhiyun 	CMD_INC_RESID(CURRENT_SC, -GETSTCNT());
2066*4882a593Smuzhiyun 
2067*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
2068*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, 0);
2069*4882a593Smuzhiyun }
2070*4882a593Smuzhiyun 
2071*4882a593Smuzhiyun /*
2072*4882a593Smuzhiyun  * data out phase
2073*4882a593Smuzhiyun  *
2074*4882a593Smuzhiyun  */
datao_init(struct Scsi_Host * shpnt)2075*4882a593Smuzhiyun static void datao_init(struct Scsi_Host *shpnt)
2076*4882a593Smuzhiyun {
2077*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
2078*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
2079*4882a593Smuzhiyun 
2080*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
2081*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
2082*4882a593Smuzhiyun 
2083*4882a593Smuzhiyun 	SETPORT(SIMODE0, 0);
2084*4882a593Smuzhiyun 	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	DATA_LEN = scsi_get_resid(CURRENT_SC);
2087*4882a593Smuzhiyun }
2088*4882a593Smuzhiyun 
datao_run(struct Scsi_Host * shpnt)2089*4882a593Smuzhiyun static void datao_run(struct Scsi_Host *shpnt)
2090*4882a593Smuzhiyun {
2091*4882a593Smuzhiyun 	unsigned long the_time;
2092*4882a593Smuzhiyun 	int data_count;
2093*4882a593Smuzhiyun 
2094*4882a593Smuzhiyun 	/* until phase changes or all data sent */
2095*4882a593Smuzhiyun 	while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) {
2096*4882a593Smuzhiyun 		data_count = 128;
2097*4882a593Smuzhiyun 		if(data_count > CURRENT_SC->SCp.this_residual)
2098*4882a593Smuzhiyun 			data_count=CURRENT_SC->SCp.this_residual;
2099*4882a593Smuzhiyun 
2100*4882a593Smuzhiyun 		if(TESTLO(DMASTAT, DFIFOEMP)) {
2101*4882a593Smuzhiyun 			scmd_printk(KERN_ERR, CURRENT_SC,
2102*4882a593Smuzhiyun 				    "datao fifo not empty (%d)",
2103*4882a593Smuzhiyun 				    GETPORT(FIFOSTAT));
2104*4882a593Smuzhiyun 			break;
2105*4882a593Smuzhiyun 		}
2106*4882a593Smuzhiyun 
2107*4882a593Smuzhiyun 		if(data_count & 1) {
2108*4882a593Smuzhiyun 			SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
2109*4882a593Smuzhiyun 			SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
2110*4882a593Smuzhiyun 			CURRENT_SC->SCp.this_residual--;
2111*4882a593Smuzhiyun 			CMD_INC_RESID(CURRENT_SC, -1);
2112*4882a593Smuzhiyun 			SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
2113*4882a593Smuzhiyun 		}
2114*4882a593Smuzhiyun 
2115*4882a593Smuzhiyun 		if(data_count > 1) {
2116*4882a593Smuzhiyun 			data_count >>= 1;
2117*4882a593Smuzhiyun 			outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
2118*4882a593Smuzhiyun 			CURRENT_SC->SCp.ptr           += 2 * data_count;
2119*4882a593Smuzhiyun 			CURRENT_SC->SCp.this_residual -= 2 * data_count;
2120*4882a593Smuzhiyun 			CMD_INC_RESID(CURRENT_SC, -2 * data_count);
2121*4882a593Smuzhiyun 		}
2122*4882a593Smuzhiyun 
2123*4882a593Smuzhiyun 		if (CURRENT_SC->SCp.this_residual == 0 &&
2124*4882a593Smuzhiyun 		    !sg_is_last(CURRENT_SC->SCp.buffer)) {
2125*4882a593Smuzhiyun 			/* advance to next buffer */
2126*4882a593Smuzhiyun 			CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer);
2127*4882a593Smuzhiyun 			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
2128*4882a593Smuzhiyun 			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
2129*4882a593Smuzhiyun 		}
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 		the_time=jiffies + 100*HZ;
2132*4882a593Smuzhiyun 		while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
2133*4882a593Smuzhiyun 			barrier();
2134*4882a593Smuzhiyun 
2135*4882a593Smuzhiyun 		if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
2136*4882a593Smuzhiyun 			scmd_printk(KERN_ERR, CURRENT_SC, "dataout timeout\n");
2137*4882a593Smuzhiyun 			break;
2138*4882a593Smuzhiyun 		}
2139*4882a593Smuzhiyun 	}
2140*4882a593Smuzhiyun }
2141*4882a593Smuzhiyun 
datao_end(struct Scsi_Host * shpnt)2142*4882a593Smuzhiyun static void datao_end(struct Scsi_Host *shpnt)
2143*4882a593Smuzhiyun {
2144*4882a593Smuzhiyun 	if(TESTLO(DMASTAT, DFIFOEMP)) {
2145*4882a593Smuzhiyun 		u32 datao_cnt = GETSTCNT();
2146*4882a593Smuzhiyun 		int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC);
2147*4882a593Smuzhiyun 		int done;
2148*4882a593Smuzhiyun 		struct scatterlist *sg = scsi_sglist(CURRENT_SC);
2149*4882a593Smuzhiyun 
2150*4882a593Smuzhiyun 		CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt);
2151*4882a593Smuzhiyun 
2152*4882a593Smuzhiyun 		done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC);
2153*4882a593Smuzhiyun 		/* Locate the first SG entry not yet sent */
2154*4882a593Smuzhiyun 		while (done > 0 && !sg_is_last(sg)) {
2155*4882a593Smuzhiyun 			if (done < sg->length)
2156*4882a593Smuzhiyun 				break;
2157*4882a593Smuzhiyun 			done -= sg->length;
2158*4882a593Smuzhiyun 			sg = sg_next(sg);
2159*4882a593Smuzhiyun 		}
2160*4882a593Smuzhiyun 
2161*4882a593Smuzhiyun 		CURRENT_SC->SCp.buffer = sg;
2162*4882a593Smuzhiyun 		CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done;
2163*4882a593Smuzhiyun 		CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length -
2164*4882a593Smuzhiyun 			done;
2165*4882a593Smuzhiyun 	}
2166*4882a593Smuzhiyun 
2167*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
2168*4882a593Smuzhiyun 	SETPORT(SXFRCTL0, CH1);
2169*4882a593Smuzhiyun 
2170*4882a593Smuzhiyun 	SETPORT(DMACNTRL0, 0);
2171*4882a593Smuzhiyun }
2172*4882a593Smuzhiyun 
2173*4882a593Smuzhiyun /*
2174*4882a593Smuzhiyun  * figure out what state we're in
2175*4882a593Smuzhiyun  *
2176*4882a593Smuzhiyun  */
update_state(struct Scsi_Host * shpnt)2177*4882a593Smuzhiyun static int update_state(struct Scsi_Host *shpnt)
2178*4882a593Smuzhiyun {
2179*4882a593Smuzhiyun 	int dataphase=0;
2180*4882a593Smuzhiyun 	unsigned int stat0 = GETPORT(SSTAT0);
2181*4882a593Smuzhiyun 	unsigned int stat1 = GETPORT(SSTAT1);
2182*4882a593Smuzhiyun 
2183*4882a593Smuzhiyun 	PREVSTATE = STATE;
2184*4882a593Smuzhiyun 	STATE=unknown;
2185*4882a593Smuzhiyun 
2186*4882a593Smuzhiyun 	if(stat1 & SCSIRSTI) {
2187*4882a593Smuzhiyun 		STATE=rsti;
2188*4882a593Smuzhiyun 		SETPORT(SCSISEQ,0);
2189*4882a593Smuzhiyun 		SETPORT(SSTAT1,SCSIRSTI);
2190*4882a593Smuzhiyun 	} else if (stat0 & SELDI && PREVSTATE == busfree) {
2191*4882a593Smuzhiyun 		STATE=seldi;
2192*4882a593Smuzhiyun 	} else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) {
2193*4882a593Smuzhiyun 		STATE=seldo;
2194*4882a593Smuzhiyun 	} else if(stat1 & SELTO) {
2195*4882a593Smuzhiyun 		STATE=selto;
2196*4882a593Smuzhiyun 	} else if(stat1 & BUSFREE) {
2197*4882a593Smuzhiyun 		STATE=busfree;
2198*4882a593Smuzhiyun 		SETPORT(SSTAT1,BUSFREE);
2199*4882a593Smuzhiyun 	} else if(stat1 & SCSIPERR) {
2200*4882a593Smuzhiyun 		STATE=parerr;
2201*4882a593Smuzhiyun 		SETPORT(SSTAT1,SCSIPERR);
2202*4882a593Smuzhiyun 	} else if(stat1 & REQINIT) {
2203*4882a593Smuzhiyun 		switch(GETPORT(SCSISIG) & P_MASK) {
2204*4882a593Smuzhiyun 		case P_MSGI:	STATE=msgi;	break;
2205*4882a593Smuzhiyun 		case P_MSGO:	STATE=msgo;	break;
2206*4882a593Smuzhiyun 		case P_DATAO:	STATE=datao;	break;
2207*4882a593Smuzhiyun 		case P_DATAI:	STATE=datai;	break;
2208*4882a593Smuzhiyun 		case P_STATUS:	STATE=status;	break;
2209*4882a593Smuzhiyun 		case P_CMD:	STATE=cmd;	break;
2210*4882a593Smuzhiyun 		}
2211*4882a593Smuzhiyun 		dataphase=1;
2212*4882a593Smuzhiyun 	}
2213*4882a593Smuzhiyun 
2214*4882a593Smuzhiyun 	if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
2215*4882a593Smuzhiyun 		scmd_printk(KERN_INFO, CURRENT_SC, "reselection missed?");
2216*4882a593Smuzhiyun 	}
2217*4882a593Smuzhiyun 
2218*4882a593Smuzhiyun 	if(STATE!=PREVSTATE) {
2219*4882a593Smuzhiyun 		LASTSTATE=PREVSTATE;
2220*4882a593Smuzhiyun 	}
2221*4882a593Smuzhiyun 
2222*4882a593Smuzhiyun 	return dataphase;
2223*4882a593Smuzhiyun }
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun /*
2226*4882a593Smuzhiyun  * handle parity error
2227*4882a593Smuzhiyun  *
2228*4882a593Smuzhiyun  * FIXME: in which phase?
2229*4882a593Smuzhiyun  *
2230*4882a593Smuzhiyun  */
parerr_run(struct Scsi_Host * shpnt)2231*4882a593Smuzhiyun static void parerr_run(struct Scsi_Host *shpnt)
2232*4882a593Smuzhiyun {
2233*4882a593Smuzhiyun 	scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n");
2234*4882a593Smuzhiyun 	done(shpnt, DID_PARITY << 16);
2235*4882a593Smuzhiyun }
2236*4882a593Smuzhiyun 
2237*4882a593Smuzhiyun /*
2238*4882a593Smuzhiyun  * handle reset in
2239*4882a593Smuzhiyun  *
2240*4882a593Smuzhiyun  */
rsti_run(struct Scsi_Host * shpnt)2241*4882a593Smuzhiyun static void rsti_run(struct Scsi_Host *shpnt)
2242*4882a593Smuzhiyun {
2243*4882a593Smuzhiyun 	struct scsi_cmnd *ptr;
2244*4882a593Smuzhiyun 
2245*4882a593Smuzhiyun 	shost_printk(KERN_NOTICE, shpnt, "scsi reset in\n");
2246*4882a593Smuzhiyun 
2247*4882a593Smuzhiyun 	ptr=DISCONNECTED_SC;
2248*4882a593Smuzhiyun 	while(ptr) {
2249*4882a593Smuzhiyun 		struct scsi_cmnd *next = SCNEXT(ptr);
2250*4882a593Smuzhiyun 
2251*4882a593Smuzhiyun 		if (!ptr->device->soft_reset) {
2252*4882a593Smuzhiyun 			remove_SC(&DISCONNECTED_SC, ptr);
2253*4882a593Smuzhiyun 
2254*4882a593Smuzhiyun 			kfree(ptr->host_scribble);
2255*4882a593Smuzhiyun 			ptr->host_scribble=NULL;
2256*4882a593Smuzhiyun 
2257*4882a593Smuzhiyun 			ptr->result =  DID_RESET << 16;
2258*4882a593Smuzhiyun 			ptr->scsi_done(ptr);
2259*4882a593Smuzhiyun 		}
2260*4882a593Smuzhiyun 
2261*4882a593Smuzhiyun 		ptr = next;
2262*4882a593Smuzhiyun 	}
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 	if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
2265*4882a593Smuzhiyun 		done(shpnt, DID_RESET << 16 );
2266*4882a593Smuzhiyun }
2267*4882a593Smuzhiyun 
2268*4882a593Smuzhiyun 
2269*4882a593Smuzhiyun /*
2270*4882a593Smuzhiyun  * bottom-half handler
2271*4882a593Smuzhiyun  *
2272*4882a593Smuzhiyun  */
is_complete(struct Scsi_Host * shpnt)2273*4882a593Smuzhiyun static void is_complete(struct Scsi_Host *shpnt)
2274*4882a593Smuzhiyun {
2275*4882a593Smuzhiyun 	int dataphase;
2276*4882a593Smuzhiyun 	unsigned long flags;
2277*4882a593Smuzhiyun 	int pending;
2278*4882a593Smuzhiyun 
2279*4882a593Smuzhiyun 	if(!shpnt)
2280*4882a593Smuzhiyun 		return;
2281*4882a593Smuzhiyun 
2282*4882a593Smuzhiyun 	DO_LOCK(flags);
2283*4882a593Smuzhiyun 
2284*4882a593Smuzhiyun 	if( HOSTDATA(shpnt)->service==0 )  {
2285*4882a593Smuzhiyun 		DO_UNLOCK(flags);
2286*4882a593Smuzhiyun 		return;
2287*4882a593Smuzhiyun 	}
2288*4882a593Smuzhiyun 
2289*4882a593Smuzhiyun 	HOSTDATA(shpnt)->service = 0;
2290*4882a593Smuzhiyun 
2291*4882a593Smuzhiyun 	if(HOSTDATA(shpnt)->in_intr) {
2292*4882a593Smuzhiyun 		DO_UNLOCK(flags);
2293*4882a593Smuzhiyun 		/* aha152x_error never returns.. */
2294*4882a593Smuzhiyun 		aha152x_error(shpnt, "bottom-half already running!?");
2295*4882a593Smuzhiyun 	}
2296*4882a593Smuzhiyun 	HOSTDATA(shpnt)->in_intr++;
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun 	/*
2299*4882a593Smuzhiyun 	 * loop while there are interrupt conditions pending
2300*4882a593Smuzhiyun 	 *
2301*4882a593Smuzhiyun 	 */
2302*4882a593Smuzhiyun 	do {
2303*4882a593Smuzhiyun 		unsigned long start = jiffies;
2304*4882a593Smuzhiyun 		DO_UNLOCK(flags);
2305*4882a593Smuzhiyun 
2306*4882a593Smuzhiyun 		dataphase=update_state(shpnt);
2307*4882a593Smuzhiyun 
2308*4882a593Smuzhiyun 		/*
2309*4882a593Smuzhiyun 		 * end previous state
2310*4882a593Smuzhiyun 		 *
2311*4882a593Smuzhiyun 		 */
2312*4882a593Smuzhiyun 		if(PREVSTATE!=STATE && states[PREVSTATE].end)
2313*4882a593Smuzhiyun 			states[PREVSTATE].end(shpnt);
2314*4882a593Smuzhiyun 
2315*4882a593Smuzhiyun 		/*
2316*4882a593Smuzhiyun 		 * disable SPIO mode if previous phase used it
2317*4882a593Smuzhiyun 		 * and this one doesn't
2318*4882a593Smuzhiyun 		 *
2319*4882a593Smuzhiyun 		 */
2320*4882a593Smuzhiyun 		if(states[PREVSTATE].spio && !states[STATE].spio) {
2321*4882a593Smuzhiyun 			SETPORT(SXFRCTL0, CH1);
2322*4882a593Smuzhiyun 			SETPORT(DMACNTRL0, 0);
2323*4882a593Smuzhiyun 			if(CURRENT_SC)
2324*4882a593Smuzhiyun 				CURRENT_SC->SCp.phase &= ~spiordy;
2325*4882a593Smuzhiyun 		}
2326*4882a593Smuzhiyun 
2327*4882a593Smuzhiyun 		/*
2328*4882a593Smuzhiyun 		 * accept current dataphase phase
2329*4882a593Smuzhiyun 		 *
2330*4882a593Smuzhiyun 		 */
2331*4882a593Smuzhiyun 		if(dataphase) {
2332*4882a593Smuzhiyun 			SETPORT(SSTAT0, REQINIT);
2333*4882a593Smuzhiyun 			SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
2334*4882a593Smuzhiyun 			SETPORT(SSTAT1, PHASECHG);
2335*4882a593Smuzhiyun 		}
2336*4882a593Smuzhiyun 
2337*4882a593Smuzhiyun 		/*
2338*4882a593Smuzhiyun 		 * enable SPIO mode if previous didn't use it
2339*4882a593Smuzhiyun 		 * and this one does
2340*4882a593Smuzhiyun 		 *
2341*4882a593Smuzhiyun 		 */
2342*4882a593Smuzhiyun 		if(!states[PREVSTATE].spio && states[STATE].spio) {
2343*4882a593Smuzhiyun 			SETPORT(DMACNTRL0, 0);
2344*4882a593Smuzhiyun 			SETPORT(SXFRCTL0, CH1|SPIOEN);
2345*4882a593Smuzhiyun 			if(CURRENT_SC)
2346*4882a593Smuzhiyun 				CURRENT_SC->SCp.phase |= spiordy;
2347*4882a593Smuzhiyun 		}
2348*4882a593Smuzhiyun 
2349*4882a593Smuzhiyun 		/*
2350*4882a593Smuzhiyun 		 * initialize for new state
2351*4882a593Smuzhiyun 		 *
2352*4882a593Smuzhiyun 		 */
2353*4882a593Smuzhiyun 		if(PREVSTATE!=STATE && states[STATE].init)
2354*4882a593Smuzhiyun 			states[STATE].init(shpnt);
2355*4882a593Smuzhiyun 
2356*4882a593Smuzhiyun 		/*
2357*4882a593Smuzhiyun 		 * handle current state
2358*4882a593Smuzhiyun 		 *
2359*4882a593Smuzhiyun 		 */
2360*4882a593Smuzhiyun 		if(states[STATE].run)
2361*4882a593Smuzhiyun 			states[STATE].run(shpnt);
2362*4882a593Smuzhiyun 		else
2363*4882a593Smuzhiyun 			scmd_printk(KERN_ERR, CURRENT_SC,
2364*4882a593Smuzhiyun 				    "unexpected state (%x)\n", STATE);
2365*4882a593Smuzhiyun 
2366*4882a593Smuzhiyun 		/*
2367*4882a593Smuzhiyun 		 * setup controller to interrupt on
2368*4882a593Smuzhiyun 		 * the next expected condition and
2369*4882a593Smuzhiyun 		 * loop if it's already there
2370*4882a593Smuzhiyun 		 *
2371*4882a593Smuzhiyun 		 */
2372*4882a593Smuzhiyun 		DO_LOCK(flags);
2373*4882a593Smuzhiyun 		pending=setup_expected_interrupts(shpnt);
2374*4882a593Smuzhiyun #if defined(AHA152X_STAT)
2375*4882a593Smuzhiyun 		HOSTDATA(shpnt)->count[STATE]++;
2376*4882a593Smuzhiyun 		if(PREVSTATE!=STATE)
2377*4882a593Smuzhiyun 			HOSTDATA(shpnt)->count_trans[STATE]++;
2378*4882a593Smuzhiyun 		HOSTDATA(shpnt)->time[STATE] += jiffies-start;
2379*4882a593Smuzhiyun #endif
2380*4882a593Smuzhiyun 
2381*4882a593Smuzhiyun 	} while(pending);
2382*4882a593Smuzhiyun 
2383*4882a593Smuzhiyun 	/*
2384*4882a593Smuzhiyun 	 * enable interrupts and leave bottom-half
2385*4882a593Smuzhiyun 	 *
2386*4882a593Smuzhiyun 	 */
2387*4882a593Smuzhiyun 	HOSTDATA(shpnt)->in_intr--;
2388*4882a593Smuzhiyun 	SETBITS(DMACNTRL0, INTEN);
2389*4882a593Smuzhiyun 	DO_UNLOCK(flags);
2390*4882a593Smuzhiyun }
2391*4882a593Smuzhiyun 
2392*4882a593Smuzhiyun 
2393*4882a593Smuzhiyun /*
2394*4882a593Smuzhiyun  * Dump the current driver status and panic
2395*4882a593Smuzhiyun  */
aha152x_error(struct Scsi_Host * shpnt,char * msg)2396*4882a593Smuzhiyun static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
2397*4882a593Smuzhiyun {
2398*4882a593Smuzhiyun 	shost_printk(KERN_EMERG, shpnt, "%s\n", msg);
2399*4882a593Smuzhiyun 	show_queues(shpnt);
2400*4882a593Smuzhiyun 	panic("aha152x panic\n");
2401*4882a593Smuzhiyun }
2402*4882a593Smuzhiyun 
2403*4882a593Smuzhiyun /*
2404*4882a593Smuzhiyun  * display enabled interrupts
2405*4882a593Smuzhiyun  */
disp_enintr(struct Scsi_Host * shpnt)2406*4882a593Smuzhiyun static void disp_enintr(struct Scsi_Host *shpnt)
2407*4882a593Smuzhiyun {
2408*4882a593Smuzhiyun 	int s0, s1;
2409*4882a593Smuzhiyun 
2410*4882a593Smuzhiyun 	s0 = GETPORT(SIMODE0);
2411*4882a593Smuzhiyun 	s1 = GETPORT(SIMODE1);
2412*4882a593Smuzhiyun 
2413*4882a593Smuzhiyun 	shost_printk(KERN_DEBUG, shpnt,
2414*4882a593Smuzhiyun 		     "enabled interrupts (%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
2415*4882a593Smuzhiyun 		     (s0 & ENSELDO) ? "ENSELDO " : "",
2416*4882a593Smuzhiyun 		     (s0 & ENSELDI) ? "ENSELDI " : "",
2417*4882a593Smuzhiyun 		     (s0 & ENSELINGO) ? "ENSELINGO " : "",
2418*4882a593Smuzhiyun 		     (s0 & ENSWRAP) ? "ENSWRAP " : "",
2419*4882a593Smuzhiyun 		     (s0 & ENSDONE) ? "ENSDONE " : "",
2420*4882a593Smuzhiyun 		     (s0 & ENSPIORDY) ? "ENSPIORDY " : "",
2421*4882a593Smuzhiyun 		     (s0 & ENDMADONE) ? "ENDMADONE " : "",
2422*4882a593Smuzhiyun 		     (s1 & ENSELTIMO) ? "ENSELTIMO " : "",
2423*4882a593Smuzhiyun 		     (s1 & ENATNTARG) ? "ENATNTARG " : "",
2424*4882a593Smuzhiyun 		     (s1 & ENPHASEMIS) ? "ENPHASEMIS " : "",
2425*4882a593Smuzhiyun 		     (s1 & ENBUSFREE) ? "ENBUSFREE " : "",
2426*4882a593Smuzhiyun 		     (s1 & ENSCSIPERR) ? "ENSCSIPERR " : "",
2427*4882a593Smuzhiyun 		     (s1 & ENPHASECHG) ? "ENPHASECHG " : "",
2428*4882a593Smuzhiyun 		     (s1 & ENREQINIT) ? "ENREQINIT " : "");
2429*4882a593Smuzhiyun }
2430*4882a593Smuzhiyun 
2431*4882a593Smuzhiyun /*
2432*4882a593Smuzhiyun  * Show the command data of a command
2433*4882a593Smuzhiyun  */
show_command(struct scsi_cmnd * ptr)2434*4882a593Smuzhiyun static void show_command(struct scsi_cmnd *ptr)
2435*4882a593Smuzhiyun {
2436*4882a593Smuzhiyun 	scsi_print_command(ptr);
2437*4882a593Smuzhiyun 	scmd_printk(KERN_DEBUG, ptr,
2438*4882a593Smuzhiyun 		    "request_bufflen=%d; resid=%d; "
2439*4882a593Smuzhiyun 		    "phase |%s%s%s%s%s%s%s%s%s; next=0x%p",
2440*4882a593Smuzhiyun 		    scsi_bufflen(ptr), scsi_get_resid(ptr),
2441*4882a593Smuzhiyun 		    (ptr->SCp.phase & not_issued) ? "not issued|" : "",
2442*4882a593Smuzhiyun 		    (ptr->SCp.phase & selecting) ? "selecting|" : "",
2443*4882a593Smuzhiyun 		    (ptr->SCp.phase & identified) ? "identified|" : "",
2444*4882a593Smuzhiyun 		    (ptr->SCp.phase & disconnected) ? "disconnected|" : "",
2445*4882a593Smuzhiyun 		    (ptr->SCp.phase & completed) ? "completed|" : "",
2446*4882a593Smuzhiyun 		    (ptr->SCp.phase & spiordy) ? "spiordy|" : "",
2447*4882a593Smuzhiyun 		    (ptr->SCp.phase & syncneg) ? "syncneg|" : "",
2448*4882a593Smuzhiyun 		    (ptr->SCp.phase & aborted) ? "aborted|" : "",
2449*4882a593Smuzhiyun 		    (ptr->SCp.phase & resetted) ? "resetted|" : "",
2450*4882a593Smuzhiyun 		    (SCDATA(ptr)) ? SCNEXT(ptr) : NULL);
2451*4882a593Smuzhiyun }
2452*4882a593Smuzhiyun 
2453*4882a593Smuzhiyun /*
2454*4882a593Smuzhiyun  * Dump the queued data
2455*4882a593Smuzhiyun  */
show_queues(struct Scsi_Host * shpnt)2456*4882a593Smuzhiyun static void show_queues(struct Scsi_Host *shpnt)
2457*4882a593Smuzhiyun {
2458*4882a593Smuzhiyun 	struct scsi_cmnd *ptr;
2459*4882a593Smuzhiyun 	unsigned long flags;
2460*4882a593Smuzhiyun 
2461*4882a593Smuzhiyun 	DO_LOCK(flags);
2462*4882a593Smuzhiyun 	printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n");
2463*4882a593Smuzhiyun 	for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
2464*4882a593Smuzhiyun 		show_command(ptr);
2465*4882a593Smuzhiyun 	DO_UNLOCK(flags);
2466*4882a593Smuzhiyun 
2467*4882a593Smuzhiyun 	printk(KERN_DEBUG "current_SC:\n");
2468*4882a593Smuzhiyun 	if (CURRENT_SC)
2469*4882a593Smuzhiyun 		show_command(CURRENT_SC);
2470*4882a593Smuzhiyun 	else
2471*4882a593Smuzhiyun 		printk(KERN_DEBUG "none\n");
2472*4882a593Smuzhiyun 
2473*4882a593Smuzhiyun 	printk(KERN_DEBUG "disconnected_SC:\n");
2474*4882a593Smuzhiyun 	for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL)
2475*4882a593Smuzhiyun 		show_command(ptr);
2476*4882a593Smuzhiyun 
2477*4882a593Smuzhiyun 	disp_enintr(shpnt);
2478*4882a593Smuzhiyun }
2479*4882a593Smuzhiyun 
get_command(struct seq_file * m,struct scsi_cmnd * ptr)2480*4882a593Smuzhiyun static void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
2481*4882a593Smuzhiyun {
2482*4882a593Smuzhiyun 	int i;
2483*4882a593Smuzhiyun 
2484*4882a593Smuzhiyun 	seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ",
2485*4882a593Smuzhiyun 		ptr, ptr->device->id, (u8)ptr->device->lun);
2486*4882a593Smuzhiyun 
2487*4882a593Smuzhiyun 	for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
2488*4882a593Smuzhiyun 		seq_printf(m, "0x%02x ", ptr->cmnd[i]);
2489*4882a593Smuzhiyun 
2490*4882a593Smuzhiyun 	seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
2491*4882a593Smuzhiyun 		scsi_get_resid(ptr), ptr->SCp.this_residual,
2492*4882a593Smuzhiyun 		sg_nents(ptr->SCp.buffer) - 1);
2493*4882a593Smuzhiyun 
2494*4882a593Smuzhiyun 	if (ptr->SCp.phase & not_issued)
2495*4882a593Smuzhiyun 		seq_puts(m, "not issued|");
2496*4882a593Smuzhiyun 	if (ptr->SCp.phase & selecting)
2497*4882a593Smuzhiyun 		seq_puts(m, "selecting|");
2498*4882a593Smuzhiyun 	if (ptr->SCp.phase & disconnected)
2499*4882a593Smuzhiyun 		seq_puts(m, "disconnected|");
2500*4882a593Smuzhiyun 	if (ptr->SCp.phase & aborted)
2501*4882a593Smuzhiyun 		seq_puts(m, "aborted|");
2502*4882a593Smuzhiyun 	if (ptr->SCp.phase & identified)
2503*4882a593Smuzhiyun 		seq_puts(m, "identified|");
2504*4882a593Smuzhiyun 	if (ptr->SCp.phase & completed)
2505*4882a593Smuzhiyun 		seq_puts(m, "completed|");
2506*4882a593Smuzhiyun 	if (ptr->SCp.phase & spiordy)
2507*4882a593Smuzhiyun 		seq_puts(m, "spiordy|");
2508*4882a593Smuzhiyun 	if (ptr->SCp.phase & syncneg)
2509*4882a593Smuzhiyun 		seq_puts(m, "syncneg|");
2510*4882a593Smuzhiyun 	seq_printf(m, "; next=0x%p\n", SCNEXT(ptr));
2511*4882a593Smuzhiyun }
2512*4882a593Smuzhiyun 
get_ports(struct seq_file * m,struct Scsi_Host * shpnt)2513*4882a593Smuzhiyun static void get_ports(struct seq_file *m, struct Scsi_Host *shpnt)
2514*4882a593Smuzhiyun {
2515*4882a593Smuzhiyun 	int s;
2516*4882a593Smuzhiyun 
2517*4882a593Smuzhiyun 	seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
2518*4882a593Smuzhiyun 
2519*4882a593Smuzhiyun 	s = GETPORT(SCSISEQ);
2520*4882a593Smuzhiyun 	seq_puts(m, "SCSISEQ( ");
2521*4882a593Smuzhiyun 	if (s & TEMODEO)
2522*4882a593Smuzhiyun 		seq_puts(m, "TARGET MODE ");
2523*4882a593Smuzhiyun 	if (s & ENSELO)
2524*4882a593Smuzhiyun 		seq_puts(m, "SELO ");
2525*4882a593Smuzhiyun 	if (s & ENSELI)
2526*4882a593Smuzhiyun 		seq_puts(m, "SELI ");
2527*4882a593Smuzhiyun 	if (s & ENRESELI)
2528*4882a593Smuzhiyun 		seq_puts(m, "RESELI ");
2529*4882a593Smuzhiyun 	if (s & ENAUTOATNO)
2530*4882a593Smuzhiyun 		seq_puts(m, "AUTOATNO ");
2531*4882a593Smuzhiyun 	if (s & ENAUTOATNI)
2532*4882a593Smuzhiyun 		seq_puts(m, "AUTOATNI ");
2533*4882a593Smuzhiyun 	if (s & ENAUTOATNP)
2534*4882a593Smuzhiyun 		seq_puts(m, "AUTOATNP ");
2535*4882a593Smuzhiyun 	if (s & SCSIRSTO)
2536*4882a593Smuzhiyun 		seq_puts(m, "SCSIRSTO ");
2537*4882a593Smuzhiyun 	seq_puts(m, ");");
2538*4882a593Smuzhiyun 
2539*4882a593Smuzhiyun 	seq_puts(m, " SCSISIG(");
2540*4882a593Smuzhiyun 	s = GETPORT(SCSISIG);
2541*4882a593Smuzhiyun 	switch (s & P_MASK) {
2542*4882a593Smuzhiyun 	case P_DATAO:
2543*4882a593Smuzhiyun 		seq_puts(m, "DATA OUT");
2544*4882a593Smuzhiyun 		break;
2545*4882a593Smuzhiyun 	case P_DATAI:
2546*4882a593Smuzhiyun 		seq_puts(m, "DATA IN");
2547*4882a593Smuzhiyun 		break;
2548*4882a593Smuzhiyun 	case P_CMD:
2549*4882a593Smuzhiyun 		seq_puts(m, "COMMAND");
2550*4882a593Smuzhiyun 		break;
2551*4882a593Smuzhiyun 	case P_STATUS:
2552*4882a593Smuzhiyun 		seq_puts(m, "STATUS");
2553*4882a593Smuzhiyun 		break;
2554*4882a593Smuzhiyun 	case P_MSGO:
2555*4882a593Smuzhiyun 		seq_puts(m, "MESSAGE OUT");
2556*4882a593Smuzhiyun 		break;
2557*4882a593Smuzhiyun 	case P_MSGI:
2558*4882a593Smuzhiyun 		seq_puts(m, "MESSAGE IN");
2559*4882a593Smuzhiyun 		break;
2560*4882a593Smuzhiyun 	default:
2561*4882a593Smuzhiyun 		seq_puts(m, "*invalid*");
2562*4882a593Smuzhiyun 		break;
2563*4882a593Smuzhiyun 	}
2564*4882a593Smuzhiyun 
2565*4882a593Smuzhiyun 	seq_puts(m, "); ");
2566*4882a593Smuzhiyun 
2567*4882a593Smuzhiyun 	seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
2568*4882a593Smuzhiyun 
2569*4882a593Smuzhiyun 	seq_puts(m, "SSTAT( ");
2570*4882a593Smuzhiyun 	s = GETPORT(SSTAT0);
2571*4882a593Smuzhiyun 	if (s & TARGET)
2572*4882a593Smuzhiyun 		seq_puts(m, "TARGET ");
2573*4882a593Smuzhiyun 	if (s & SELDO)
2574*4882a593Smuzhiyun 		seq_puts(m, "SELDO ");
2575*4882a593Smuzhiyun 	if (s & SELDI)
2576*4882a593Smuzhiyun 		seq_puts(m, "SELDI ");
2577*4882a593Smuzhiyun 	if (s & SELINGO)
2578*4882a593Smuzhiyun 		seq_puts(m, "SELINGO ");
2579*4882a593Smuzhiyun 	if (s & SWRAP)
2580*4882a593Smuzhiyun 		seq_puts(m, "SWRAP ");
2581*4882a593Smuzhiyun 	if (s & SDONE)
2582*4882a593Smuzhiyun 		seq_puts(m, "SDONE ");
2583*4882a593Smuzhiyun 	if (s & SPIORDY)
2584*4882a593Smuzhiyun 		seq_puts(m, "SPIORDY ");
2585*4882a593Smuzhiyun 	if (s & DMADONE)
2586*4882a593Smuzhiyun 		seq_puts(m, "DMADONE ");
2587*4882a593Smuzhiyun 
2588*4882a593Smuzhiyun 	s = GETPORT(SSTAT1);
2589*4882a593Smuzhiyun 	if (s & SELTO)
2590*4882a593Smuzhiyun 		seq_puts(m, "SELTO ");
2591*4882a593Smuzhiyun 	if (s & ATNTARG)
2592*4882a593Smuzhiyun 		seq_puts(m, "ATNTARG ");
2593*4882a593Smuzhiyun 	if (s & SCSIRSTI)
2594*4882a593Smuzhiyun 		seq_puts(m, "SCSIRSTI ");
2595*4882a593Smuzhiyun 	if (s & PHASEMIS)
2596*4882a593Smuzhiyun 		seq_puts(m, "PHASEMIS ");
2597*4882a593Smuzhiyun 	if (s & BUSFREE)
2598*4882a593Smuzhiyun 		seq_puts(m, "BUSFREE ");
2599*4882a593Smuzhiyun 	if (s & SCSIPERR)
2600*4882a593Smuzhiyun 		seq_puts(m, "SCSIPERR ");
2601*4882a593Smuzhiyun 	if (s & PHASECHG)
2602*4882a593Smuzhiyun 		seq_puts(m, "PHASECHG ");
2603*4882a593Smuzhiyun 	if (s & REQINIT)
2604*4882a593Smuzhiyun 		seq_puts(m, "REQINIT ");
2605*4882a593Smuzhiyun 	seq_puts(m, "); ");
2606*4882a593Smuzhiyun 
2607*4882a593Smuzhiyun 
2608*4882a593Smuzhiyun 	seq_puts(m, "SSTAT( ");
2609*4882a593Smuzhiyun 
2610*4882a593Smuzhiyun 	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
2611*4882a593Smuzhiyun 
2612*4882a593Smuzhiyun 	if (s & TARGET)
2613*4882a593Smuzhiyun 		seq_puts(m, "TARGET ");
2614*4882a593Smuzhiyun 	if (s & SELDO)
2615*4882a593Smuzhiyun 		seq_puts(m, "SELDO ");
2616*4882a593Smuzhiyun 	if (s & SELDI)
2617*4882a593Smuzhiyun 		seq_puts(m, "SELDI ");
2618*4882a593Smuzhiyun 	if (s & SELINGO)
2619*4882a593Smuzhiyun 		seq_puts(m, "SELINGO ");
2620*4882a593Smuzhiyun 	if (s & SWRAP)
2621*4882a593Smuzhiyun 		seq_puts(m, "SWRAP ");
2622*4882a593Smuzhiyun 	if (s & SDONE)
2623*4882a593Smuzhiyun 		seq_puts(m, "SDONE ");
2624*4882a593Smuzhiyun 	if (s & SPIORDY)
2625*4882a593Smuzhiyun 		seq_puts(m, "SPIORDY ");
2626*4882a593Smuzhiyun 	if (s & DMADONE)
2627*4882a593Smuzhiyun 		seq_puts(m, "DMADONE ");
2628*4882a593Smuzhiyun 
2629*4882a593Smuzhiyun 	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
2630*4882a593Smuzhiyun 
2631*4882a593Smuzhiyun 	if (s & SELTO)
2632*4882a593Smuzhiyun 		seq_puts(m, "SELTO ");
2633*4882a593Smuzhiyun 	if (s & ATNTARG)
2634*4882a593Smuzhiyun 		seq_puts(m, "ATNTARG ");
2635*4882a593Smuzhiyun 	if (s & SCSIRSTI)
2636*4882a593Smuzhiyun 		seq_puts(m, "SCSIRSTI ");
2637*4882a593Smuzhiyun 	if (s & PHASEMIS)
2638*4882a593Smuzhiyun 		seq_puts(m, "PHASEMIS ");
2639*4882a593Smuzhiyun 	if (s & BUSFREE)
2640*4882a593Smuzhiyun 		seq_puts(m, "BUSFREE ");
2641*4882a593Smuzhiyun 	if (s & SCSIPERR)
2642*4882a593Smuzhiyun 		seq_puts(m, "SCSIPERR ");
2643*4882a593Smuzhiyun 	if (s & PHASECHG)
2644*4882a593Smuzhiyun 		seq_puts(m, "PHASECHG ");
2645*4882a593Smuzhiyun 	if (s & REQINIT)
2646*4882a593Smuzhiyun 		seq_puts(m, "REQINIT ");
2647*4882a593Smuzhiyun 	seq_puts(m, "); ");
2648*4882a593Smuzhiyun 
2649*4882a593Smuzhiyun 	seq_puts(m, "SXFRCTL0( ");
2650*4882a593Smuzhiyun 
2651*4882a593Smuzhiyun 	s = GETPORT(SXFRCTL0);
2652*4882a593Smuzhiyun 	if (s & SCSIEN)
2653*4882a593Smuzhiyun 		seq_puts(m, "SCSIEN ");
2654*4882a593Smuzhiyun 	if (s & DMAEN)
2655*4882a593Smuzhiyun 		seq_puts(m, "DMAEN ");
2656*4882a593Smuzhiyun 	if (s & CH1)
2657*4882a593Smuzhiyun 		seq_puts(m, "CH1 ");
2658*4882a593Smuzhiyun 	if (s & CLRSTCNT)
2659*4882a593Smuzhiyun 		seq_puts(m, "CLRSTCNT ");
2660*4882a593Smuzhiyun 	if (s & SPIOEN)
2661*4882a593Smuzhiyun 		seq_puts(m, "SPIOEN ");
2662*4882a593Smuzhiyun 	if (s & CLRCH1)
2663*4882a593Smuzhiyun 		seq_puts(m, "CLRCH1 ");
2664*4882a593Smuzhiyun 	seq_puts(m, "); ");
2665*4882a593Smuzhiyun 
2666*4882a593Smuzhiyun 	seq_puts(m, "SIGNAL( ");
2667*4882a593Smuzhiyun 
2668*4882a593Smuzhiyun 	s = GETPORT(SCSISIG);
2669*4882a593Smuzhiyun 	if (s & SIG_ATNI)
2670*4882a593Smuzhiyun 		seq_puts(m, "ATNI ");
2671*4882a593Smuzhiyun 	if (s & SIG_SELI)
2672*4882a593Smuzhiyun 		seq_puts(m, "SELI ");
2673*4882a593Smuzhiyun 	if (s & SIG_BSYI)
2674*4882a593Smuzhiyun 		seq_puts(m, "BSYI ");
2675*4882a593Smuzhiyun 	if (s & SIG_REQI)
2676*4882a593Smuzhiyun 		seq_puts(m, "REQI ");
2677*4882a593Smuzhiyun 	if (s & SIG_ACKI)
2678*4882a593Smuzhiyun 		seq_puts(m, "ACKI ");
2679*4882a593Smuzhiyun 	seq_puts(m, "); ");
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun 	seq_printf(m, "SELID(%02x), ", GETPORT(SELID));
2682*4882a593Smuzhiyun 
2683*4882a593Smuzhiyun 	seq_printf(m, "STCNT(%d), ", GETSTCNT());
2684*4882a593Smuzhiyun 
2685*4882a593Smuzhiyun 	seq_puts(m, "SSTAT2( ");
2686*4882a593Smuzhiyun 
2687*4882a593Smuzhiyun 	s = GETPORT(SSTAT2);
2688*4882a593Smuzhiyun 	if (s & SOFFSET)
2689*4882a593Smuzhiyun 		seq_puts(m, "SOFFSET ");
2690*4882a593Smuzhiyun 	if (s & SEMPTY)
2691*4882a593Smuzhiyun 		seq_puts(m, "SEMPTY ");
2692*4882a593Smuzhiyun 	if (s & SFULL)
2693*4882a593Smuzhiyun 		seq_puts(m, "SFULL ");
2694*4882a593Smuzhiyun 	seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT));
2695*4882a593Smuzhiyun 
2696*4882a593Smuzhiyun 	s = GETPORT(SSTAT3);
2697*4882a593Smuzhiyun 	seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
2698*4882a593Smuzhiyun 
2699*4882a593Smuzhiyun 	seq_puts(m, "SSTAT4( ");
2700*4882a593Smuzhiyun 	s = GETPORT(SSTAT4);
2701*4882a593Smuzhiyun 	if (s & SYNCERR)
2702*4882a593Smuzhiyun 		seq_puts(m, "SYNCERR ");
2703*4882a593Smuzhiyun 	if (s & FWERR)
2704*4882a593Smuzhiyun 		seq_puts(m, "FWERR ");
2705*4882a593Smuzhiyun 	if (s & FRERR)
2706*4882a593Smuzhiyun 		seq_puts(m, "FRERR ");
2707*4882a593Smuzhiyun 	seq_puts(m, "); ");
2708*4882a593Smuzhiyun 
2709*4882a593Smuzhiyun 	seq_puts(m, "DMACNTRL0( ");
2710*4882a593Smuzhiyun 	s = GETPORT(DMACNTRL0);
2711*4882a593Smuzhiyun 	seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT");
2712*4882a593Smuzhiyun 	seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO");
2713*4882a593Smuzhiyun 	seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ");
2714*4882a593Smuzhiyun 	if (s & ENDMA)
2715*4882a593Smuzhiyun 		seq_puts(m, "ENDMA ");
2716*4882a593Smuzhiyun 	if (s & INTEN)
2717*4882a593Smuzhiyun 		seq_puts(m, "INTEN ");
2718*4882a593Smuzhiyun 	if (s & RSTFIFO)
2719*4882a593Smuzhiyun 		seq_puts(m, "RSTFIFO ");
2720*4882a593Smuzhiyun 	if (s & SWINT)
2721*4882a593Smuzhiyun 		seq_puts(m, "SWINT ");
2722*4882a593Smuzhiyun 	seq_puts(m, "); ");
2723*4882a593Smuzhiyun 
2724*4882a593Smuzhiyun 	seq_puts(m, "DMASTAT( ");
2725*4882a593Smuzhiyun 	s = GETPORT(DMASTAT);
2726*4882a593Smuzhiyun 	if (s & ATDONE)
2727*4882a593Smuzhiyun 		seq_puts(m, "ATDONE ");
2728*4882a593Smuzhiyun 	if (s & WORDRDY)
2729*4882a593Smuzhiyun 		seq_puts(m, "WORDRDY ");
2730*4882a593Smuzhiyun 	if (s & DFIFOFULL)
2731*4882a593Smuzhiyun 		seq_puts(m, "DFIFOFULL ");
2732*4882a593Smuzhiyun 	if (s & DFIFOEMP)
2733*4882a593Smuzhiyun 		seq_puts(m, "DFIFOEMP ");
2734*4882a593Smuzhiyun 	seq_puts(m, ")\n");
2735*4882a593Smuzhiyun 
2736*4882a593Smuzhiyun 	seq_puts(m, "enabled interrupts( ");
2737*4882a593Smuzhiyun 
2738*4882a593Smuzhiyun 	s = GETPORT(SIMODE0);
2739*4882a593Smuzhiyun 	if (s & ENSELDO)
2740*4882a593Smuzhiyun 		seq_puts(m, "ENSELDO ");
2741*4882a593Smuzhiyun 	if (s & ENSELDI)
2742*4882a593Smuzhiyun 		seq_puts(m, "ENSELDI ");
2743*4882a593Smuzhiyun 	if (s & ENSELINGO)
2744*4882a593Smuzhiyun 		seq_puts(m, "ENSELINGO ");
2745*4882a593Smuzhiyun 	if (s & ENSWRAP)
2746*4882a593Smuzhiyun 		seq_puts(m, "ENSWRAP ");
2747*4882a593Smuzhiyun 	if (s & ENSDONE)
2748*4882a593Smuzhiyun 		seq_puts(m, "ENSDONE ");
2749*4882a593Smuzhiyun 	if (s & ENSPIORDY)
2750*4882a593Smuzhiyun 		seq_puts(m, "ENSPIORDY ");
2751*4882a593Smuzhiyun 	if (s & ENDMADONE)
2752*4882a593Smuzhiyun 		seq_puts(m, "ENDMADONE ");
2753*4882a593Smuzhiyun 
2754*4882a593Smuzhiyun 	s = GETPORT(SIMODE1);
2755*4882a593Smuzhiyun 	if (s & ENSELTIMO)
2756*4882a593Smuzhiyun 		seq_puts(m, "ENSELTIMO ");
2757*4882a593Smuzhiyun 	if (s & ENATNTARG)
2758*4882a593Smuzhiyun 		seq_puts(m, "ENATNTARG ");
2759*4882a593Smuzhiyun 	if (s & ENPHASEMIS)
2760*4882a593Smuzhiyun 		seq_puts(m, "ENPHASEMIS ");
2761*4882a593Smuzhiyun 	if (s & ENBUSFREE)
2762*4882a593Smuzhiyun 		seq_puts(m, "ENBUSFREE ");
2763*4882a593Smuzhiyun 	if (s & ENSCSIPERR)
2764*4882a593Smuzhiyun 		seq_puts(m, "ENSCSIPERR ");
2765*4882a593Smuzhiyun 	if (s & ENPHASECHG)
2766*4882a593Smuzhiyun 		seq_puts(m, "ENPHASECHG ");
2767*4882a593Smuzhiyun 	if (s & ENREQINIT)
2768*4882a593Smuzhiyun 		seq_puts(m, "ENREQINIT ");
2769*4882a593Smuzhiyun 	seq_puts(m, ")\n");
2770*4882a593Smuzhiyun }
2771*4882a593Smuzhiyun 
aha152x_set_info(struct Scsi_Host * shpnt,char * buffer,int length)2772*4882a593Smuzhiyun static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
2773*4882a593Smuzhiyun {
2774*4882a593Smuzhiyun 	if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
2775*4882a593Smuzhiyun 		return -EINVAL;
2776*4882a593Smuzhiyun 
2777*4882a593Smuzhiyun #if defined(AHA152X_STAT)
2778*4882a593Smuzhiyun 	if(length>13 && strncmp("reset", buffer+8, 5)==0) {
2779*4882a593Smuzhiyun 		int i;
2780*4882a593Smuzhiyun 
2781*4882a593Smuzhiyun 		HOSTDATA(shpnt)->total_commands=0;
2782*4882a593Smuzhiyun 		HOSTDATA(shpnt)->disconnections=0;
2783*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_any_action=0;
2784*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_old_command=0;
2785*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_new_command=0;
2786*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_done_command=0;
2787*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_with_check_condition=0;
2788*4882a593Smuzhiyun 		for (i = idle; i<maxstate; i++) {
2789*4882a593Smuzhiyun 			HOSTDATA(shpnt)->count[i]=0;
2790*4882a593Smuzhiyun 			HOSTDATA(shpnt)->count_trans[i]=0;
2791*4882a593Smuzhiyun 			HOSTDATA(shpnt)->time[i]=0;
2792*4882a593Smuzhiyun 		}
2793*4882a593Smuzhiyun 
2794*4882a593Smuzhiyun 		shost_printk(KERN_INFO, shpnt, "aha152x: stats reset.\n");
2795*4882a593Smuzhiyun 
2796*4882a593Smuzhiyun 	} else
2797*4882a593Smuzhiyun #endif
2798*4882a593Smuzhiyun 	{
2799*4882a593Smuzhiyun 		return -EINVAL;
2800*4882a593Smuzhiyun 	}
2801*4882a593Smuzhiyun 
2802*4882a593Smuzhiyun 
2803*4882a593Smuzhiyun 	return length;
2804*4882a593Smuzhiyun }
2805*4882a593Smuzhiyun 
aha152x_show_info(struct seq_file * m,struct Scsi_Host * shpnt)2806*4882a593Smuzhiyun static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
2807*4882a593Smuzhiyun {
2808*4882a593Smuzhiyun 	int i;
2809*4882a593Smuzhiyun 	struct scsi_cmnd *ptr;
2810*4882a593Smuzhiyun 	unsigned long flags;
2811*4882a593Smuzhiyun 
2812*4882a593Smuzhiyun 	seq_puts(m, AHA152X_REVID "\n");
2813*4882a593Smuzhiyun 
2814*4882a593Smuzhiyun 	seq_printf(m, "ioports 0x%04lx to 0x%04lx\n",
2815*4882a593Smuzhiyun 		shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
2816*4882a593Smuzhiyun 	seq_printf(m, "interrupt 0x%02x\n", shpnt->irq);
2817*4882a593Smuzhiyun 	seq_printf(m, "disconnection/reconnection %s\n",
2818*4882a593Smuzhiyun 		RECONNECT ? "enabled" : "disabled");
2819*4882a593Smuzhiyun 	seq_printf(m, "parity checking %s\n",
2820*4882a593Smuzhiyun 		PARITY ? "enabled" : "disabled");
2821*4882a593Smuzhiyun 	seq_printf(m, "synchronous transfers %s\n",
2822*4882a593Smuzhiyun 		SYNCHRONOUS ? "enabled" : "disabled");
2823*4882a593Smuzhiyun 	seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands);
2824*4882a593Smuzhiyun 
2825*4882a593Smuzhiyun 	if(SYNCHRONOUS) {
2826*4882a593Smuzhiyun 		seq_puts(m, "synchronously operating targets (tick=50 ns):\n");
2827*4882a593Smuzhiyun 		for (i = 0; i < 8; i++)
2828*4882a593Smuzhiyun 			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
2829*4882a593Smuzhiyun 				seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n",
2830*4882a593Smuzhiyun 					i,
2831*4882a593Smuzhiyun 					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
2832*4882a593Smuzhiyun 					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
2833*4882a593Smuzhiyun 				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
2834*4882a593Smuzhiyun 	}
2835*4882a593Smuzhiyun 	seq_puts(m, "\nqueue status:\n");
2836*4882a593Smuzhiyun 	DO_LOCK(flags);
2837*4882a593Smuzhiyun 	if (ISSUE_SC) {
2838*4882a593Smuzhiyun 		seq_puts(m, "not yet issued commands:\n");
2839*4882a593Smuzhiyun 		for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
2840*4882a593Smuzhiyun 			get_command(m, ptr);
2841*4882a593Smuzhiyun 	} else
2842*4882a593Smuzhiyun 		seq_puts(m, "no not yet issued commands\n");
2843*4882a593Smuzhiyun 	DO_UNLOCK(flags);
2844*4882a593Smuzhiyun 
2845*4882a593Smuzhiyun 	if (CURRENT_SC) {
2846*4882a593Smuzhiyun 		seq_puts(m, "current command:\n");
2847*4882a593Smuzhiyun 		get_command(m, CURRENT_SC);
2848*4882a593Smuzhiyun 	} else
2849*4882a593Smuzhiyun 		seq_puts(m, "no current command\n");
2850*4882a593Smuzhiyun 
2851*4882a593Smuzhiyun 	if (DISCONNECTED_SC) {
2852*4882a593Smuzhiyun 		seq_puts(m, "disconnected commands:\n");
2853*4882a593Smuzhiyun 		for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
2854*4882a593Smuzhiyun 			get_command(m, ptr);
2855*4882a593Smuzhiyun 	} else
2856*4882a593Smuzhiyun 		seq_puts(m, "no disconnected commands\n");
2857*4882a593Smuzhiyun 
2858*4882a593Smuzhiyun 	get_ports(m, shpnt);
2859*4882a593Smuzhiyun 
2860*4882a593Smuzhiyun #if defined(AHA152X_STAT)
2861*4882a593Smuzhiyun 	seq_printf(m, "statistics:\n"
2862*4882a593Smuzhiyun 		"total commands:               %d\n"
2863*4882a593Smuzhiyun 		"disconnections:               %d\n"
2864*4882a593Smuzhiyun 		"busfree with check condition: %d\n"
2865*4882a593Smuzhiyun 		"busfree without old command:  %d\n"
2866*4882a593Smuzhiyun 		"busfree without new command:  %d\n"
2867*4882a593Smuzhiyun 		"busfree without done command: %d\n"
2868*4882a593Smuzhiyun 		"busfree without any action:   %d\n"
2869*4882a593Smuzhiyun 		"state      "
2870*4882a593Smuzhiyun 		"transitions  "
2871*4882a593Smuzhiyun 		"count        "
2872*4882a593Smuzhiyun 		"time\n",
2873*4882a593Smuzhiyun 		HOSTDATA(shpnt)->total_commands,
2874*4882a593Smuzhiyun 		HOSTDATA(shpnt)->disconnections,
2875*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_with_check_condition,
2876*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_old_command,
2877*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_new_command,
2878*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_done_command,
2879*4882a593Smuzhiyun 		HOSTDATA(shpnt)->busfree_without_any_action);
2880*4882a593Smuzhiyun 	for(i=0; i<maxstate; i++) {
2881*4882a593Smuzhiyun 		seq_printf(m, "%-10s %-12d %-12d %-12ld\n",
2882*4882a593Smuzhiyun 			states[i].name,
2883*4882a593Smuzhiyun 			HOSTDATA(shpnt)->count_trans[i],
2884*4882a593Smuzhiyun 			HOSTDATA(shpnt)->count[i],
2885*4882a593Smuzhiyun 			HOSTDATA(shpnt)->time[i]);
2886*4882a593Smuzhiyun 	}
2887*4882a593Smuzhiyun #endif
2888*4882a593Smuzhiyun 	return 0;
2889*4882a593Smuzhiyun }
2890*4882a593Smuzhiyun 
aha152x_adjust_queue(struct scsi_device * device)2891*4882a593Smuzhiyun static int aha152x_adjust_queue(struct scsi_device *device)
2892*4882a593Smuzhiyun {
2893*4882a593Smuzhiyun 	blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
2894*4882a593Smuzhiyun 	return 0;
2895*4882a593Smuzhiyun }
2896*4882a593Smuzhiyun 
2897*4882a593Smuzhiyun static struct scsi_host_template aha152x_driver_template = {
2898*4882a593Smuzhiyun 	.module				= THIS_MODULE,
2899*4882a593Smuzhiyun 	.name				= AHA152X_REVID,
2900*4882a593Smuzhiyun 	.proc_name			= "aha152x",
2901*4882a593Smuzhiyun 	.show_info			= aha152x_show_info,
2902*4882a593Smuzhiyun 	.write_info			= aha152x_set_info,
2903*4882a593Smuzhiyun 	.queuecommand			= aha152x_queue,
2904*4882a593Smuzhiyun 	.eh_abort_handler		= aha152x_abort,
2905*4882a593Smuzhiyun 	.eh_device_reset_handler	= aha152x_device_reset,
2906*4882a593Smuzhiyun 	.eh_bus_reset_handler		= aha152x_bus_reset,
2907*4882a593Smuzhiyun 	.bios_param			= aha152x_biosparam,
2908*4882a593Smuzhiyun 	.can_queue			= 1,
2909*4882a593Smuzhiyun 	.this_id			= 7,
2910*4882a593Smuzhiyun 	.sg_tablesize			= SG_ALL,
2911*4882a593Smuzhiyun 	.dma_boundary			= PAGE_SIZE - 1,
2912*4882a593Smuzhiyun 	.slave_alloc			= aha152x_adjust_queue,
2913*4882a593Smuzhiyun };
2914*4882a593Smuzhiyun 
2915*4882a593Smuzhiyun #if !defined(AHA152X_PCMCIA)
2916*4882a593Smuzhiyun static int setup_count;
2917*4882a593Smuzhiyun static struct aha152x_setup setup[2];
2918*4882a593Smuzhiyun 
2919*4882a593Smuzhiyun /* possible i/o addresses for the AIC-6260; default first */
2920*4882a593Smuzhiyun static unsigned short ports[] = { 0x340, 0x140 };
2921*4882a593Smuzhiyun 
2922*4882a593Smuzhiyun #if !defined(SKIP_BIOSTEST)
2923*4882a593Smuzhiyun /* possible locations for the Adaptec BIOS; defaults first */
2924*4882a593Smuzhiyun static unsigned int addresses[] =
2925*4882a593Smuzhiyun {
2926*4882a593Smuzhiyun 	0xdc000,		/* default first */
2927*4882a593Smuzhiyun 	0xc8000,
2928*4882a593Smuzhiyun 	0xcc000,
2929*4882a593Smuzhiyun 	0xd0000,
2930*4882a593Smuzhiyun 	0xd4000,
2931*4882a593Smuzhiyun 	0xd8000,
2932*4882a593Smuzhiyun 	0xe0000,
2933*4882a593Smuzhiyun 	0xeb800,		/* VTech Platinum SMP */
2934*4882a593Smuzhiyun 	0xf0000,
2935*4882a593Smuzhiyun };
2936*4882a593Smuzhiyun 
2937*4882a593Smuzhiyun /* signatures for various AIC-6[23]60 based controllers.
2938*4882a593Smuzhiyun    The point in detecting signatures is to avoid useless and maybe
2939*4882a593Smuzhiyun    harmful probes on ports. I'm not sure that all listed boards pass
2940*4882a593Smuzhiyun    auto-configuration. For those which fail the BIOS signature is
2941*4882a593Smuzhiyun    obsolete, because user intervention to supply the configuration is
2942*4882a593Smuzhiyun    needed anyway.  May be an information whether or not the BIOS supports
2943*4882a593Smuzhiyun    extended translation could be also useful here. */
2944*4882a593Smuzhiyun static struct signature {
2945*4882a593Smuzhiyun 	unsigned char *signature;
2946*4882a593Smuzhiyun 	int sig_offset;
2947*4882a593Smuzhiyun 	int sig_length;
2948*4882a593Smuzhiyun } signatures[] =
2949*4882a593Smuzhiyun {
2950*4882a593Smuzhiyun 	{ "Adaptec AHA-1520 BIOS",	0x102e, 21 },
2951*4882a593Smuzhiyun 		/* Adaptec 152x */
2952*4882a593Smuzhiyun 	{ "Adaptec AHA-1520B",		0x000b, 17 },
2953*4882a593Smuzhiyun 		/* Adaptec 152x rev B */
2954*4882a593Smuzhiyun 	{ "Adaptec AHA-1520B",		0x0026, 17 },
2955*4882a593Smuzhiyun 		/* Iomega Jaz Jet ISA (AIC6370Q) */
2956*4882a593Smuzhiyun 	{ "Adaptec ASW-B626 BIOS",	0x1029, 21 },
2957*4882a593Smuzhiyun 		/* on-board controller */
2958*4882a593Smuzhiyun 	{ "Adaptec BIOS: ASW-B626",	0x000f, 22 },
2959*4882a593Smuzhiyun 		/* on-board controller */
2960*4882a593Smuzhiyun 	{ "Adaptec ASW-B626 S2",	0x2e6c, 19 },
2961*4882a593Smuzhiyun 		/* on-board controller */
2962*4882a593Smuzhiyun 	{ "Adaptec BIOS:AIC-6360",	0x000c, 21 },
2963*4882a593Smuzhiyun 		/* on-board controller */
2964*4882a593Smuzhiyun 	{ "ScsiPro SP-360 BIOS",	0x2873, 19 },
2965*4882a593Smuzhiyun 		/* ScsiPro-Controller  */
2966*4882a593Smuzhiyun 	{ "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
2967*4882a593Smuzhiyun 		/* Gigabyte Local-Bus-SCSI */
2968*4882a593Smuzhiyun 	{ "Adaptec BIOS:AVA-282X",	0x000c, 21 },
2969*4882a593Smuzhiyun 		/* Adaptec 282x */
2970*4882a593Smuzhiyun 	{ "Adaptec IBM Dock II SCSI",   0x2edd, 24 },
2971*4882a593Smuzhiyun 		/* IBM Thinkpad Dock II */
2972*4882a593Smuzhiyun 	{ "Adaptec BIOS:AHA-1532P",     0x001c, 22 },
2973*4882a593Smuzhiyun 		/* IBM Thinkpad Dock II SCSI */
2974*4882a593Smuzhiyun 	{ "DTC3520A Host Adapter BIOS", 0x318a, 26 },
2975*4882a593Smuzhiyun 		/* DTC 3520A ISA SCSI */
2976*4882a593Smuzhiyun };
2977*4882a593Smuzhiyun #endif /* !SKIP_BIOSTEST */
2978*4882a593Smuzhiyun 
2979*4882a593Smuzhiyun /*
2980*4882a593Smuzhiyun  * Test, if port_base is valid.
2981*4882a593Smuzhiyun  *
2982*4882a593Smuzhiyun  */
aha152x_porttest(int io_port)2983*4882a593Smuzhiyun static int aha152x_porttest(int io_port)
2984*4882a593Smuzhiyun {
2985*4882a593Smuzhiyun 	int i;
2986*4882a593Smuzhiyun 
2987*4882a593Smuzhiyun 	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
2988*4882a593Smuzhiyun 	for (i = 0; i < 16; i++)
2989*4882a593Smuzhiyun 		SETPORT(io_port + O_STACK, i);
2990*4882a593Smuzhiyun 
2991*4882a593Smuzhiyun 	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
2992*4882a593Smuzhiyun 	for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
2993*4882a593Smuzhiyun 		;
2994*4882a593Smuzhiyun 
2995*4882a593Smuzhiyun 	return (i == 16);
2996*4882a593Smuzhiyun }
2997*4882a593Smuzhiyun 
tc1550_porttest(int io_port)2998*4882a593Smuzhiyun static int tc1550_porttest(int io_port)
2999*4882a593Smuzhiyun {
3000*4882a593Smuzhiyun 	int i;
3001*4882a593Smuzhiyun 
3002*4882a593Smuzhiyun 	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
3003*4882a593Smuzhiyun 	for (i = 0; i < 16; i++)
3004*4882a593Smuzhiyun 		SETPORT(io_port + O_STACK, i);
3005*4882a593Smuzhiyun 
3006*4882a593Smuzhiyun 	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
3007*4882a593Smuzhiyun 	for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
3008*4882a593Smuzhiyun 		;
3009*4882a593Smuzhiyun 
3010*4882a593Smuzhiyun 	return (i == 16);
3011*4882a593Smuzhiyun }
3012*4882a593Smuzhiyun 
3013*4882a593Smuzhiyun 
checksetup(struct aha152x_setup * setup)3014*4882a593Smuzhiyun static int checksetup(struct aha152x_setup *setup)
3015*4882a593Smuzhiyun {
3016*4882a593Smuzhiyun 	int i;
3017*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++)
3018*4882a593Smuzhiyun 		;
3019*4882a593Smuzhiyun 
3020*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(ports))
3021*4882a593Smuzhiyun 		return 0;
3022*4882a593Smuzhiyun 
3023*4882a593Smuzhiyun 	if (!request_region(setup->io_port, IO_RANGE, "aha152x")) {
3024*4882a593Smuzhiyun 		printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
3025*4882a593Smuzhiyun 		return 0;
3026*4882a593Smuzhiyun 	}
3027*4882a593Smuzhiyun 
3028*4882a593Smuzhiyun 	if( aha152x_porttest(setup->io_port) ) {
3029*4882a593Smuzhiyun 		setup->tc1550=0;
3030*4882a593Smuzhiyun 	} else if( tc1550_porttest(setup->io_port) ) {
3031*4882a593Smuzhiyun 		setup->tc1550=1;
3032*4882a593Smuzhiyun 	} else {
3033*4882a593Smuzhiyun 		release_region(setup->io_port, IO_RANGE);
3034*4882a593Smuzhiyun 		return 0;
3035*4882a593Smuzhiyun 	}
3036*4882a593Smuzhiyun 
3037*4882a593Smuzhiyun 	release_region(setup->io_port, IO_RANGE);
3038*4882a593Smuzhiyun 
3039*4882a593Smuzhiyun 	if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
3040*4882a593Smuzhiyun 		return 0;
3041*4882a593Smuzhiyun 
3042*4882a593Smuzhiyun 	if ((setup->scsiid < 0) || (setup->scsiid > 7))
3043*4882a593Smuzhiyun 		return 0;
3044*4882a593Smuzhiyun 
3045*4882a593Smuzhiyun 	if ((setup->reconnect < 0) || (setup->reconnect > 1))
3046*4882a593Smuzhiyun 		return 0;
3047*4882a593Smuzhiyun 
3048*4882a593Smuzhiyun 	if ((setup->parity < 0) || (setup->parity > 1))
3049*4882a593Smuzhiyun 		return 0;
3050*4882a593Smuzhiyun 
3051*4882a593Smuzhiyun 	if ((setup->synchronous < 0) || (setup->synchronous > 1))
3052*4882a593Smuzhiyun 		return 0;
3053*4882a593Smuzhiyun 
3054*4882a593Smuzhiyun 	if ((setup->ext_trans < 0) || (setup->ext_trans > 1))
3055*4882a593Smuzhiyun 		return 0;
3056*4882a593Smuzhiyun 
3057*4882a593Smuzhiyun 
3058*4882a593Smuzhiyun 	return 1;
3059*4882a593Smuzhiyun }
3060*4882a593Smuzhiyun 
3061*4882a593Smuzhiyun 
aha152x_init(void)3062*4882a593Smuzhiyun static int __init aha152x_init(void)
3063*4882a593Smuzhiyun {
3064*4882a593Smuzhiyun 	int i, j, ok;
3065*4882a593Smuzhiyun #if defined(AUTOCONF)
3066*4882a593Smuzhiyun 	aha152x_config conf;
3067*4882a593Smuzhiyun #endif
3068*4882a593Smuzhiyun #ifdef __ISAPNP__
3069*4882a593Smuzhiyun 	struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL};
3070*4882a593Smuzhiyun #endif
3071*4882a593Smuzhiyun 
3072*4882a593Smuzhiyun 	if ( setup_count ) {
3073*4882a593Smuzhiyun 		printk(KERN_INFO "aha152x: processing commandline: ");
3074*4882a593Smuzhiyun 
3075*4882a593Smuzhiyun 		for (i = 0; i<setup_count; i++) {
3076*4882a593Smuzhiyun 			if (!checksetup(&setup[i])) {
3077*4882a593Smuzhiyun 				printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
3078*4882a593Smuzhiyun 				printk(KERN_ERR "aha152x: invalid line\n");
3079*4882a593Smuzhiyun 			}
3080*4882a593Smuzhiyun 		}
3081*4882a593Smuzhiyun 		printk("ok\n");
3082*4882a593Smuzhiyun 	}
3083*4882a593Smuzhiyun 
3084*4882a593Smuzhiyun #if defined(SETUP0)
3085*4882a593Smuzhiyun 	if (setup_count < ARRAY_SIZE(setup)) {
3086*4882a593Smuzhiyun 		struct aha152x_setup override = SETUP0;
3087*4882a593Smuzhiyun 
3088*4882a593Smuzhiyun 		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
3089*4882a593Smuzhiyun 			if (!checksetup(&override)) {
3090*4882a593Smuzhiyun 				printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
3091*4882a593Smuzhiyun 				       override.io_port,
3092*4882a593Smuzhiyun 				       override.irq,
3093*4882a593Smuzhiyun 				       override.scsiid,
3094*4882a593Smuzhiyun 				       override.reconnect,
3095*4882a593Smuzhiyun 				       override.parity,
3096*4882a593Smuzhiyun 				       override.synchronous,
3097*4882a593Smuzhiyun 				       override.delay,
3098*4882a593Smuzhiyun 				       override.ext_trans);
3099*4882a593Smuzhiyun 			} else
3100*4882a593Smuzhiyun 				setup[setup_count++] = override;
3101*4882a593Smuzhiyun 		}
3102*4882a593Smuzhiyun 	}
3103*4882a593Smuzhiyun #endif
3104*4882a593Smuzhiyun 
3105*4882a593Smuzhiyun #if defined(SETUP1)
3106*4882a593Smuzhiyun 	if (setup_count < ARRAY_SIZE(setup)) {
3107*4882a593Smuzhiyun 		struct aha152x_setup override = SETUP1;
3108*4882a593Smuzhiyun 
3109*4882a593Smuzhiyun 		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
3110*4882a593Smuzhiyun 			if (!checksetup(&override)) {
3111*4882a593Smuzhiyun 				printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
3112*4882a593Smuzhiyun 				       override.io_port,
3113*4882a593Smuzhiyun 				       override.irq,
3114*4882a593Smuzhiyun 				       override.scsiid,
3115*4882a593Smuzhiyun 				       override.reconnect,
3116*4882a593Smuzhiyun 				       override.parity,
3117*4882a593Smuzhiyun 				       override.synchronous,
3118*4882a593Smuzhiyun 				       override.delay,
3119*4882a593Smuzhiyun 				       override.ext_trans);
3120*4882a593Smuzhiyun 			} else
3121*4882a593Smuzhiyun 				setup[setup_count++] = override;
3122*4882a593Smuzhiyun 		}
3123*4882a593Smuzhiyun 	}
3124*4882a593Smuzhiyun #endif
3125*4882a593Smuzhiyun 
3126*4882a593Smuzhiyun #if defined(MODULE)
3127*4882a593Smuzhiyun 	if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
3128*4882a593Smuzhiyun 		if(aha152x[0]!=0) {
3129*4882a593Smuzhiyun 			setup[setup_count].conf        = "";
3130*4882a593Smuzhiyun 			setup[setup_count].io_port     = aha152x[0];
3131*4882a593Smuzhiyun 			setup[setup_count].irq         = aha152x[1];
3132*4882a593Smuzhiyun 			setup[setup_count].scsiid      = aha152x[2];
3133*4882a593Smuzhiyun 			setup[setup_count].reconnect   = aha152x[3];
3134*4882a593Smuzhiyun 			setup[setup_count].parity      = aha152x[4];
3135*4882a593Smuzhiyun 			setup[setup_count].synchronous = aha152x[5];
3136*4882a593Smuzhiyun 			setup[setup_count].delay       = aha152x[6];
3137*4882a593Smuzhiyun 			setup[setup_count].ext_trans   = aha152x[7];
3138*4882a593Smuzhiyun 		} else if (io[0] != 0 || irq[0] != 0) {
3139*4882a593Smuzhiyun 			if(io[0]!=0)  setup[setup_count].io_port = io[0];
3140*4882a593Smuzhiyun 			if(irq[0]!=0) setup[setup_count].irq     = irq[0];
3141*4882a593Smuzhiyun 
3142*4882a593Smuzhiyun 			setup[setup_count].scsiid      = scsiid[0];
3143*4882a593Smuzhiyun 			setup[setup_count].reconnect   = reconnect[0];
3144*4882a593Smuzhiyun 			setup[setup_count].parity      = parity[0];
3145*4882a593Smuzhiyun 			setup[setup_count].synchronous = sync[0];
3146*4882a593Smuzhiyun 			setup[setup_count].delay       = delay[0];
3147*4882a593Smuzhiyun 			setup[setup_count].ext_trans   = exttrans[0];
3148*4882a593Smuzhiyun 		}
3149*4882a593Smuzhiyun 
3150*4882a593Smuzhiyun 		if (checksetup(&setup[setup_count]))
3151*4882a593Smuzhiyun 			setup_count++;
3152*4882a593Smuzhiyun 		else
3153*4882a593Smuzhiyun 			printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
3154*4882a593Smuzhiyun 			       setup[setup_count].io_port,
3155*4882a593Smuzhiyun 			       setup[setup_count].irq,
3156*4882a593Smuzhiyun 			       setup[setup_count].scsiid,
3157*4882a593Smuzhiyun 			       setup[setup_count].reconnect,
3158*4882a593Smuzhiyun 			       setup[setup_count].parity,
3159*4882a593Smuzhiyun 			       setup[setup_count].synchronous,
3160*4882a593Smuzhiyun 			       setup[setup_count].delay,
3161*4882a593Smuzhiyun 			       setup[setup_count].ext_trans);
3162*4882a593Smuzhiyun 	}
3163*4882a593Smuzhiyun 
3164*4882a593Smuzhiyun 	if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
3165*4882a593Smuzhiyun 		if(aha152x1[0]!=0) {
3166*4882a593Smuzhiyun 			setup[setup_count].conf        = "";
3167*4882a593Smuzhiyun 			setup[setup_count].io_port     = aha152x1[0];
3168*4882a593Smuzhiyun 			setup[setup_count].irq         = aha152x1[1];
3169*4882a593Smuzhiyun 			setup[setup_count].scsiid      = aha152x1[2];
3170*4882a593Smuzhiyun 			setup[setup_count].reconnect   = aha152x1[3];
3171*4882a593Smuzhiyun 			setup[setup_count].parity      = aha152x1[4];
3172*4882a593Smuzhiyun 			setup[setup_count].synchronous = aha152x1[5];
3173*4882a593Smuzhiyun 			setup[setup_count].delay       = aha152x1[6];
3174*4882a593Smuzhiyun 			setup[setup_count].ext_trans   = aha152x1[7];
3175*4882a593Smuzhiyun 		} else if (io[1] != 0 || irq[1] != 0) {
3176*4882a593Smuzhiyun 			if(io[1]!=0)  setup[setup_count].io_port = io[1];
3177*4882a593Smuzhiyun 			if(irq[1]!=0) setup[setup_count].irq     = irq[1];
3178*4882a593Smuzhiyun 
3179*4882a593Smuzhiyun 			setup[setup_count].scsiid      = scsiid[1];
3180*4882a593Smuzhiyun 			setup[setup_count].reconnect   = reconnect[1];
3181*4882a593Smuzhiyun 			setup[setup_count].parity      = parity[1];
3182*4882a593Smuzhiyun 			setup[setup_count].synchronous = sync[1];
3183*4882a593Smuzhiyun 			setup[setup_count].delay       = delay[1];
3184*4882a593Smuzhiyun 			setup[setup_count].ext_trans   = exttrans[1];
3185*4882a593Smuzhiyun 		}
3186*4882a593Smuzhiyun 		if (checksetup(&setup[setup_count]))
3187*4882a593Smuzhiyun 			setup_count++;
3188*4882a593Smuzhiyun 		else
3189*4882a593Smuzhiyun 			printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
3190*4882a593Smuzhiyun 			       setup[setup_count].io_port,
3191*4882a593Smuzhiyun 			       setup[setup_count].irq,
3192*4882a593Smuzhiyun 			       setup[setup_count].scsiid,
3193*4882a593Smuzhiyun 			       setup[setup_count].reconnect,
3194*4882a593Smuzhiyun 			       setup[setup_count].parity,
3195*4882a593Smuzhiyun 			       setup[setup_count].synchronous,
3196*4882a593Smuzhiyun 			       setup[setup_count].delay,
3197*4882a593Smuzhiyun 			       setup[setup_count].ext_trans);
3198*4882a593Smuzhiyun 	}
3199*4882a593Smuzhiyun #endif
3200*4882a593Smuzhiyun 
3201*4882a593Smuzhiyun #ifdef __ISAPNP__
3202*4882a593Smuzhiyun 	for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) {
3203*4882a593Smuzhiyun 		while ( setup_count<ARRAY_SIZE(setup) &&
3204*4882a593Smuzhiyun 			(dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) {
3205*4882a593Smuzhiyun 			if (pnp_device_attach(dev) < 0)
3206*4882a593Smuzhiyun 				continue;
3207*4882a593Smuzhiyun 
3208*4882a593Smuzhiyun 			if (pnp_activate_dev(dev) < 0) {
3209*4882a593Smuzhiyun 				pnp_device_detach(dev);
3210*4882a593Smuzhiyun 				continue;
3211*4882a593Smuzhiyun 			}
3212*4882a593Smuzhiyun 
3213*4882a593Smuzhiyun 			if (!pnp_port_valid(dev, 0)) {
3214*4882a593Smuzhiyun 				pnp_device_detach(dev);
3215*4882a593Smuzhiyun 				continue;
3216*4882a593Smuzhiyun 			}
3217*4882a593Smuzhiyun 
3218*4882a593Smuzhiyun 			if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) {
3219*4882a593Smuzhiyun 				pnp_device_detach(dev);
3220*4882a593Smuzhiyun 				continue;
3221*4882a593Smuzhiyun 			}
3222*4882a593Smuzhiyun 
3223*4882a593Smuzhiyun 			setup[setup_count].io_port     = pnp_port_start(dev, 0);
3224*4882a593Smuzhiyun 			setup[setup_count].irq         = pnp_irq(dev, 0);
3225*4882a593Smuzhiyun 			setup[setup_count].scsiid      = 7;
3226*4882a593Smuzhiyun 			setup[setup_count].reconnect   = 1;
3227*4882a593Smuzhiyun 			setup[setup_count].parity      = 1;
3228*4882a593Smuzhiyun 			setup[setup_count].synchronous = 1;
3229*4882a593Smuzhiyun 			setup[setup_count].delay       = DELAY_DEFAULT;
3230*4882a593Smuzhiyun 			setup[setup_count].ext_trans   = 0;
3231*4882a593Smuzhiyun #if defined(__ISAPNP__)
3232*4882a593Smuzhiyun 			pnpdev[setup_count]            = dev;
3233*4882a593Smuzhiyun #endif
3234*4882a593Smuzhiyun 			printk (KERN_INFO
3235*4882a593Smuzhiyun 				"aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n",
3236*4882a593Smuzhiyun 				setup[setup_count].io_port, setup[setup_count].irq);
3237*4882a593Smuzhiyun 			setup_count++;
3238*4882a593Smuzhiyun 		}
3239*4882a593Smuzhiyun 	}
3240*4882a593Smuzhiyun #endif
3241*4882a593Smuzhiyun 
3242*4882a593Smuzhiyun #if defined(AUTOCONF)
3243*4882a593Smuzhiyun 	if (setup_count<ARRAY_SIZE(setup)) {
3244*4882a593Smuzhiyun #if !defined(SKIP_BIOSTEST)
3245*4882a593Smuzhiyun 		ok = 0;
3246*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) {
3247*4882a593Smuzhiyun 			void __iomem *p = ioremap(addresses[i], 0x4000);
3248*4882a593Smuzhiyun 			if (!p)
3249*4882a593Smuzhiyun 				continue;
3250*4882a593Smuzhiyun 			for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++)
3251*4882a593Smuzhiyun 				ok = check_signature(p + signatures[j].sig_offset,
3252*4882a593Smuzhiyun 								signatures[j].signature, signatures[j].sig_length);
3253*4882a593Smuzhiyun 			iounmap(p);
3254*4882a593Smuzhiyun 		}
3255*4882a593Smuzhiyun 		if (!ok && setup_count == 0)
3256*4882a593Smuzhiyun 			return -ENODEV;
3257*4882a593Smuzhiyun 
3258*4882a593Smuzhiyun 		printk(KERN_INFO "aha152x: BIOS test: passed, ");
3259*4882a593Smuzhiyun #else
3260*4882a593Smuzhiyun 		printk(KERN_INFO "aha152x: ");
3261*4882a593Smuzhiyun #endif				/* !SKIP_BIOSTEST */
3262*4882a593Smuzhiyun 
3263*4882a593Smuzhiyun 		ok = 0;
3264*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) {
3265*4882a593Smuzhiyun 			if ((setup_count == 1) && (setup[0].io_port == ports[i]))
3266*4882a593Smuzhiyun 				continue;
3267*4882a593Smuzhiyun 
3268*4882a593Smuzhiyun 			if (!request_region(ports[i], IO_RANGE, "aha152x")) {
3269*4882a593Smuzhiyun 				printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
3270*4882a593Smuzhiyun 				continue;
3271*4882a593Smuzhiyun 			}
3272*4882a593Smuzhiyun 
3273*4882a593Smuzhiyun 			if (aha152x_porttest(ports[i])) {
3274*4882a593Smuzhiyun 				setup[setup_count].tc1550  = 0;
3275*4882a593Smuzhiyun 
3276*4882a593Smuzhiyun 				conf.cf_port =
3277*4882a593Smuzhiyun 				    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
3278*4882a593Smuzhiyun 			} else if (tc1550_porttest(ports[i])) {
3279*4882a593Smuzhiyun 				setup[setup_count].tc1550  = 1;
3280*4882a593Smuzhiyun 
3281*4882a593Smuzhiyun 				conf.cf_port =
3282*4882a593Smuzhiyun 				    (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB);
3283*4882a593Smuzhiyun 			} else {
3284*4882a593Smuzhiyun 				release_region(ports[i], IO_RANGE);
3285*4882a593Smuzhiyun 				continue;
3286*4882a593Smuzhiyun 			}
3287*4882a593Smuzhiyun 
3288*4882a593Smuzhiyun 			release_region(ports[i], IO_RANGE);
3289*4882a593Smuzhiyun 
3290*4882a593Smuzhiyun 			ok++;
3291*4882a593Smuzhiyun 			setup[setup_count].io_port = ports[i];
3292*4882a593Smuzhiyun 			setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
3293*4882a593Smuzhiyun 			setup[setup_count].scsiid = conf.cf_id;
3294*4882a593Smuzhiyun 			setup[setup_count].reconnect = conf.cf_tardisc;
3295*4882a593Smuzhiyun 			setup[setup_count].parity = !conf.cf_parity;
3296*4882a593Smuzhiyun 			setup[setup_count].synchronous = conf.cf_syncneg;
3297*4882a593Smuzhiyun 			setup[setup_count].delay = DELAY_DEFAULT;
3298*4882a593Smuzhiyun 			setup[setup_count].ext_trans = 0;
3299*4882a593Smuzhiyun 			setup_count++;
3300*4882a593Smuzhiyun 
3301*4882a593Smuzhiyun 		}
3302*4882a593Smuzhiyun 
3303*4882a593Smuzhiyun 		if (ok)
3304*4882a593Smuzhiyun 			printk("auto configuration: ok, ");
3305*4882a593Smuzhiyun 	}
3306*4882a593Smuzhiyun #endif
3307*4882a593Smuzhiyun 
3308*4882a593Smuzhiyun 	printk("%d controller(s) configured\n", setup_count);
3309*4882a593Smuzhiyun 
3310*4882a593Smuzhiyun 	for (i=0; i<setup_count; i++) {
3311*4882a593Smuzhiyun 		if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) {
3312*4882a593Smuzhiyun 			struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]);
3313*4882a593Smuzhiyun 
3314*4882a593Smuzhiyun 			if( !shpnt ) {
3315*4882a593Smuzhiyun 				release_region(setup[i].io_port, IO_RANGE);
3316*4882a593Smuzhiyun #if defined(__ISAPNP__)
3317*4882a593Smuzhiyun 			} else if( pnpdev[i] ) {
3318*4882a593Smuzhiyun 				HOSTDATA(shpnt)->pnpdev=pnpdev[i];
3319*4882a593Smuzhiyun 				pnpdev[i]=NULL;
3320*4882a593Smuzhiyun #endif
3321*4882a593Smuzhiyun 			}
3322*4882a593Smuzhiyun 		} else {
3323*4882a593Smuzhiyun 			printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port);
3324*4882a593Smuzhiyun 		}
3325*4882a593Smuzhiyun 
3326*4882a593Smuzhiyun #if defined(__ISAPNP__)
3327*4882a593Smuzhiyun 		if( pnpdev[i] )
3328*4882a593Smuzhiyun 			pnp_device_detach(pnpdev[i]);
3329*4882a593Smuzhiyun #endif
3330*4882a593Smuzhiyun 	}
3331*4882a593Smuzhiyun 
3332*4882a593Smuzhiyun 	return 0;
3333*4882a593Smuzhiyun }
3334*4882a593Smuzhiyun 
aha152x_exit(void)3335*4882a593Smuzhiyun static void __exit aha152x_exit(void)
3336*4882a593Smuzhiyun {
3337*4882a593Smuzhiyun 	struct aha152x_hostdata *hd, *tmp;
3338*4882a593Smuzhiyun 
3339*4882a593Smuzhiyun 	list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) {
3340*4882a593Smuzhiyun 		struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
3341*4882a593Smuzhiyun 
3342*4882a593Smuzhiyun 		aha152x_release(shost);
3343*4882a593Smuzhiyun 	}
3344*4882a593Smuzhiyun }
3345*4882a593Smuzhiyun 
3346*4882a593Smuzhiyun module_init(aha152x_init);
3347*4882a593Smuzhiyun module_exit(aha152x_exit);
3348*4882a593Smuzhiyun 
3349*4882a593Smuzhiyun #if !defined(MODULE)
aha152x_setup(char * str)3350*4882a593Smuzhiyun static int __init aha152x_setup(char *str)
3351*4882a593Smuzhiyun {
3352*4882a593Smuzhiyun 	int ints[10];
3353*4882a593Smuzhiyun 
3354*4882a593Smuzhiyun 	get_options(str, ARRAY_SIZE(ints), ints);
3355*4882a593Smuzhiyun 
3356*4882a593Smuzhiyun 	if(setup_count>=ARRAY_SIZE(setup)) {
3357*4882a593Smuzhiyun 		printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
3358*4882a593Smuzhiyun 		return 1;
3359*4882a593Smuzhiyun 	}
3360*4882a593Smuzhiyun 
3361*4882a593Smuzhiyun 	setup[setup_count].conf        = str;
3362*4882a593Smuzhiyun 	setup[setup_count].io_port     = ints[0] >= 1 ? ints[1] : 0x340;
3363*4882a593Smuzhiyun 	setup[setup_count].irq         = ints[0] >= 2 ? ints[2] : 11;
3364*4882a593Smuzhiyun 	setup[setup_count].scsiid      = ints[0] >= 3 ? ints[3] : 7;
3365*4882a593Smuzhiyun 	setup[setup_count].reconnect   = ints[0] >= 4 ? ints[4] : 1;
3366*4882a593Smuzhiyun 	setup[setup_count].parity      = ints[0] >= 5 ? ints[5] : 1;
3367*4882a593Smuzhiyun 	setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
3368*4882a593Smuzhiyun 	setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
3369*4882a593Smuzhiyun 	setup[setup_count].ext_trans   = ints[0] >= 8 ? ints[8] : 0;
3370*4882a593Smuzhiyun 	if (ints[0] > 8)
3371*4882a593Smuzhiyun 		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
3372*4882a593Smuzhiyun 		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
3373*4882a593Smuzhiyun 	else
3374*4882a593Smuzhiyun 		setup_count++;
3375*4882a593Smuzhiyun 
3376*4882a593Smuzhiyun 	return 1;
3377*4882a593Smuzhiyun }
3378*4882a593Smuzhiyun __setup("aha152x=", aha152x_setup);
3379*4882a593Smuzhiyun #endif
3380*4882a593Smuzhiyun 
3381*4882a593Smuzhiyun #endif /* !AHA152X_PCMCIA */
3382