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