File: | obj-scan-build/../linux/src/drivers/scsi/qlogicfas.c |
Location: | line 406, column 3 |
Description: | Value stored to 'k' is never read |
1 | /*----------------------------------------------------------------*/ |
2 | /* |
3 | Qlogic linux driver - work in progress. No Warranty express or implied. |
4 | Use at your own risk. Support Tort Reform so you won't have to read all |
5 | these silly disclaimers. |
6 | |
7 | Copyright 1994, Tom Zerucha. |
8 | zerucha@shell.portal.com |
9 | |
10 | Additional Code, and much appreciated help by |
11 | Michael A. Griffith |
12 | grif@cs.ucr.edu |
13 | |
14 | Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA |
15 | help respectively, and for suffering through my foolishness during the |
16 | debugging process. |
17 | |
18 | Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 |
19 | (you can reference it, but it is incomplete and inaccurate in places) |
20 | |
21 | Version 0.45 6/9/96 - kernel 1.2.0+ |
22 | |
23 | Functions as standalone, loadable, and PCMCIA driver, the latter from |
24 | Dave Hind's PCMCIA package. |
25 | |
26 | Redistributable under terms of the GNU Public License |
27 | |
28 | */ |
29 | /*----------------------------------------------------------------*/ |
30 | /* Configuration */ |
31 | |
32 | /* Set the following to 2 to use normal interrupt (active high/totempole- |
33 | tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open |
34 | drain */ |
35 | #define QL_INT_ACTIVE_HIGH2 2 |
36 | |
37 | /* Set the following to 1 to enable the use of interrupts. Note that 0 tends |
38 | to be more stable, but slower (or ties up the system more) */ |
39 | #define QL_USE_IRQ1 1 |
40 | |
41 | /* Set the following to max out the speed of the PIO PseudoDMA transfers, |
42 | again, 0 tends to be slower, but more stable. */ |
43 | #define QL_TURBO_PDMA1 1 |
44 | |
45 | /* This should be 1 to enable parity detection */ |
46 | #define QL_ENABLE_PARITY1 1 |
47 | |
48 | /* This will reset all devices when the driver is initialized (during bootup). |
49 | The other linux drivers don't do this, but the DOS drivers do, and after |
50 | using DOS or some kind of crash or lockup this will bring things back |
51 | without requiring a cold boot. It does take some time to recover from a |
52 | reset, so it is slower, and I have seen timeouts so that devices weren't |
53 | recognized when this was set. */ |
54 | #define QL_RESET_AT_START0 0 |
55 | |
56 | /* crystal frequency in megahertz (for offset 5 and 9) |
57 | Please set this for your card. Most Qlogic cards are 40 Mhz. The |
58 | Control Concepts ISA (not VLB) is 24 Mhz */ |
59 | #define XTALFREQ40 40 |
60 | |
61 | /**********/ |
62 | /* DANGER! modify these at your own risk */ |
63 | /* SLOWCABLE can usually be reset to zero if you have a clean setup and |
64 | proper termination. The rest are for synchronous transfers and other |
65 | advanced features if your device can transfer faster than 5Mb/sec. |
66 | If you are really curious, email me for a quick howto until I have |
67 | something official */ |
68 | /**********/ |
69 | |
70 | /*****/ |
71 | /* config register 1 (offset 8) options */ |
72 | /* This needs to be set to 1 if your cabling is long or noisy */ |
73 | #define SLOWCABLE1 1 |
74 | |
75 | /*****/ |
76 | /* offset 0xc */ |
77 | /* This will set fast (10Mhz) synchronous timing when set to 1 |
78 | For this to have an effect, FASTCLK must also be 1 */ |
79 | #define FASTSCSI0 0 |
80 | |
81 | /* This when set to 1 will set a faster sync transfer rate */ |
82 | #define FASTCLK0 0 |
83 | /*(XTALFREQ>25?1:0)*/ |
84 | |
85 | /*****/ |
86 | /* offset 6 */ |
87 | /* This is the sync transfer divisor, XTALFREQ/X will be the maximum |
88 | achievable data rate (assuming the rest of the system is capable |
89 | and set properly) */ |
90 | #define SYNCXFRPD5 5 |
91 | /*(XTALFREQ/5)*/ |
92 | |
93 | /*****/ |
94 | /* offset 7 */ |
95 | /* This is the count of how many synchronous transfers can take place |
96 | i.e. how many reqs can occur before an ack is given. |
97 | The maximum value for this is 15, the upper bits can modify |
98 | REQ/ACK assertion and deassertion during synchronous transfers |
99 | If this is 0, the bus will only transfer asynchronously */ |
100 | #define SYNCOFFST0 0 |
101 | /* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles |
102 | of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will |
103 | cause the deassertion to be early by 1/2 clock. Bits 5&4 control |
104 | the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ |
105 | |
106 | /*----------------------------------------------------------------*/ |
107 | #ifdef PCMCIA |
108 | #undef QL_INT_ACTIVE_HIGH2 |
109 | #define QL_INT_ACTIVE_HIGH2 0 |
110 | #define MODULE |
111 | #endif |
112 | |
113 | #include <linux/module.h> |
114 | |
115 | #ifdef PCMCIA |
116 | #undef MODULE |
117 | #endif |
118 | |
119 | #include <linux/blk.h> /* to get disk capacity */ |
120 | #include <linux/kernel.h> |
121 | #include <linux/string.h> |
122 | #include <linux/ioport.h> |
123 | #include <linux/sched.h> |
124 | #include <linux/proc_fs.h> |
125 | #include <linux/unistd.h> |
126 | #include <asm/io.h> |
127 | #include <asm/irq.h> |
128 | #include "sd.h" |
129 | #include "hosts.h" |
130 | #include "qlogicfas.h" |
131 | #include<linux/stat.h> |
132 | |
133 | struct proc_dir_entry proc_scsi_qlogicfas = { |
134 | PROC_SCSI_QLOGICFAS, 6, "qlogicfas", |
135 | S_IFDIR0040000 | S_IRUGO(00400|00040|00004) | S_IXUGO(00100|00010|00001), 2 |
136 | }; |
137 | |
138 | /*----------------------------------------------------------------*/ |
139 | /* driver state info, local to driver */ |
140 | static int qbase = 0; /* Port */ |
141 | static int qinitid; /* initiator ID */ |
142 | static int qabort; /* Flag to cause an abort */ |
143 | static int qlirq = -1; /* IRQ being used */ |
144 | static char qinfo[80]; /* description */ |
145 | static Scsi_Cmnd *qlcmd; /* current command being processed */ |
146 | |
147 | static int qlcfg5 = ( XTALFREQ40 << 5 ); /* 15625/512 */ |
148 | static int qlcfg6 = SYNCXFRPD5; |
149 | static int qlcfg7 = SYNCOFFST0; |
150 | static int qlcfg8 = ( SLOWCABLE1 << 7 ) | ( QL_ENABLE_PARITY1 << 4 ); |
151 | static int qlcfg9 = ( ( XTALFREQ40 + 4 ) / 5 ); |
152 | static int qlcfgc = ( FASTCLK0 << 3 ) | ( FASTSCSI0 << 4 ); |
153 | |
154 | /*----------------------------------------------------------------*/ |
155 | /* The qlogic card uses two register maps - These macros select which one */ |
156 | #define REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))) ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd )((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), outb( 4 , qbase + 0xd )((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd)))) |
157 | #define REG1( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd))), ((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc( (0xb4 | 2),(qbase + 0xd)) : __outb((0xb4 | 2),(qbase + 0xd))) ) ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd )((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd))), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((0xb4 | 2),(qbase + 0xd)) : __outb((0xb4 | 2),(qbase + 0xd)))) |
158 | |
159 | /* following is watchdog timeout in microseconds */ |
160 | #define WATCHDOG5000000 5000000 |
161 | |
162 | /*----------------------------------------------------------------*/ |
163 | /* the following will set the monitor border color (useful to find |
164 | where something crashed or gets stuck at and as a simple profiler) */ |
165 | |
166 | #if 0 |
167 | #define rtrc(i){} {inb(0x3da)((__builtin_constant_p((0x3da)) && (0x3da) < 256) ? __inbc(0x3da) : __inb(0x3da));outb(0x31,0x3c0)((__builtin_constant_p((0x3c0)) && (0x3c0) < 256) ? __outbc((0x31),(0x3c0)) : __outb((0x31),(0x3c0)));outb((i),0x3c0)((__builtin_constant_p((0x3c0)) && (0x3c0) < 256) ? __outbc(((i)),(0x3c0)) : __outb(((i)),(0x3c0)));} |
168 | #else |
169 | #define rtrc(i){} {} |
170 | #endif |
171 | |
172 | /*----------------------------------------------------------------*/ |
173 | /* local functions */ |
174 | /*----------------------------------------------------------------*/ |
175 | static void ql_zap(void); |
176 | /* error recovery - reset everything */ |
177 | void ql_zap() |
178 | { |
179 | int x; |
180 | unsigned long flags; |
181 | save_flags( flags )__asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); |
182 | cli()__asm__ __volatile__ ("cli": : :"memory"); |
183 | x = inb(qbase + 0xd)((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)); |
184 | REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))); |
185 | outb(3, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((3),(qbase + 3)) : __outb((3),(qbase + 3))); /* reset SCSI */ |
186 | outb(2, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((2),(qbase + 3)) : __outb((2),(qbase + 3))); /* reset chip */ |
187 | if (x & 0x80) |
188 | REG1( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd))), ((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc( (0xb4 | 2),(qbase + 0xd)) : __outb((0xb4 | 2),(qbase + 0xd))) ); |
189 | restore_flags( flags )__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); |
190 | } |
191 | |
192 | /*----------------------------------------------------------------*/ |
193 | /* do pseudo-dma */ |
194 | static int ql_pdma(int phase, char *request, int reqlen) |
195 | { |
196 | int j; |
197 | j = 0; |
198 | if (phase & 1) { /* in */ |
199 | #if QL_TURBO_PDMA1 |
200 | rtrc(4){} |
201 | /* empty fifo in large chunks */ |
202 | if( reqlen >= 128 && (inb( qbase + 8 )((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8)) & 2) ) { /* full */ |
203 | insl( qbase + 4, request, 32 ); |
204 | reqlen -= 128; |
205 | request += 128; |
206 | } |
207 | while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */ |
208 | if( (j=inb( qbase + 8 )((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8))) & 4 ) { |
209 | insl( qbase + 4, request, 21 ); |
210 | reqlen -= 84; |
211 | request += 84; |
212 | } |
213 | if( reqlen >= 44 && (inb( qbase + 8 )((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8)) & 8) ) { /* 1/3 */ |
214 | insl( qbase + 4, request, 11 ); |
215 | reqlen -= 44; |
216 | request += 44; |
217 | } |
218 | #endif |
219 | /* until both empty and int (or until reclen is 0) */ |
220 | rtrc(7){} |
221 | j = 0; |
222 | while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) { |
223 | /* while bytes to receive and not empty */ |
224 | j &= 0xc0; |
225 | while ( reqlen && !( (j=inb(qbase + 8)((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8))) & 0x10 ) ) { |
226 | *request++ = inb(qbase + 4)((__builtin_constant_p((qbase + 4)) && (qbase + 4) < 256) ? __inbc(qbase + 4) : __inb(qbase + 4)); |
227 | reqlen--; |
228 | } |
229 | if( j & 0x10 ) |
230 | j = inb(qbase+8)((__builtin_constant_p((qbase+8)) && (qbase+8) < 256 ) ? __inbc(qbase+8) : __inb(qbase+8)); |
231 | |
232 | } |
233 | } |
234 | else { /* out */ |
235 | #if QL_TURBO_PDMA1 |
236 | rtrc(4){} |
237 | if( reqlen >= 128 && inb( qbase + 8 )((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8)) & 0x10 ) { /* empty */ |
238 | outsl(qbase + 4, request, 32 ); |
239 | reqlen -= 128; |
240 | request += 128; |
241 | } |
242 | while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */ |
243 | if( !((j=inb( qbase + 8 )((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8))) & 8) ) { |
244 | outsl( qbase + 4, request, 21 ); |
245 | reqlen -= 84; |
246 | request += 84; |
247 | } |
248 | if( reqlen >= 40 && !(inb( qbase + 8 )((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8)) & 4 ) ) { /* 2/3 */ |
249 | outsl( qbase + 4, request, 10 ); |
250 | reqlen -= 40; |
251 | request += 40; |
252 | } |
253 | #endif |
254 | /* until full and int (or until reclen is 0) */ |
255 | rtrc(7){} |
256 | j = 0; |
257 | while( reqlen && !( (j & 2) && (j & 0xc0) ) ) { |
258 | /* while bytes to send and not full */ |
259 | while ( reqlen && !( (j=inb(qbase + 8)((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8))) & 2 ) ) { |
260 | outb(*request++, qbase + 4)((__builtin_constant_p((qbase + 4)) && (qbase + 4) < 256) ? __outbc((*request++),(qbase + 4)) : __outb((*request++ ),(qbase + 4))); |
261 | reqlen--; |
262 | } |
263 | if( j & 2 ) |
264 | j = inb(qbase+8)((__builtin_constant_p((qbase+8)) && (qbase+8) < 256 ) ? __inbc(qbase+8) : __inb(qbase+8)); |
265 | } |
266 | } |
267 | /* maybe return reqlen */ |
268 | return inb( qbase + 8 )((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8)) & 0xc0; |
269 | } |
270 | |
271 | /*----------------------------------------------------------------*/ |
272 | /* wait for interrupt flag (polled - not real hardware interrupt) */ |
273 | static int ql_wai(void) |
274 | { |
275 | int i,k; |
276 | k = 0; |
277 | i = jiffies + WATCHDOG5000000; |
278 | while ( i > jiffies && !qabort && !((k = inb(qbase + 4)((__builtin_constant_p((qbase + 4)) && (qbase + 4) < 256) ? __inbc(qbase + 4) : __inb(qbase + 4))) & 0xe0)) |
279 | barrier()__asm__ __volatile__("": : :"memory"); |
280 | if (i <= jiffies) |
281 | return (DID_TIME_OUT0x03); |
282 | if (qabort) |
283 | return (qabort == 1 ? DID_ABORT0x05 : DID_RESET0x08); |
284 | if (k & 0x60) |
285 | ql_zap(); |
286 | if (k & 0x20) |
287 | return (DID_PARITY0x06); |
288 | if (k & 0x40) |
289 | return (DID_ERROR0x07); |
290 | return 0; |
291 | } |
292 | |
293 | /*----------------------------------------------------------------*/ |
294 | /* initiate scsi command - queueing handler */ |
295 | static void ql_icmd(Scsi_Cmnd * cmd) |
296 | { |
297 | unsigned int i; |
298 | unsigned long flags; |
299 | |
300 | qabort = 0; |
301 | |
302 | save_flags( flags )__asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); |
303 | cli()__asm__ __volatile__ ("cli": : :"memory"); |
304 | REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))); |
305 | /* clearing of interrupts and the fifo is needed */ |
306 | inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5)); /* clear interrupts */ |
307 | if (inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5))) /* if still interrupting */ |
308 | outb(2, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((2),(qbase + 3)) : __outb((2),(qbase + 3))); /* reset chip */ |
309 | else if (inb(qbase + 7)((__builtin_constant_p((qbase + 7)) && (qbase + 7) < 256) ? __inbc(qbase + 7) : __inb(qbase + 7)) & 0x1f) |
310 | outb(1, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((1),(qbase + 3)) : __outb((1),(qbase + 3))); /* clear fifo */ |
311 | while (inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5))); /* clear ints */ |
312 | REG1( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd))), ((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc( (0xb4 | 2),(qbase + 0xd)) : __outb((0xb4 | 2),(qbase + 0xd))) ); |
313 | outb(1, qbase + 8)((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __outbc((1),(qbase + 8)) : __outb((1),(qbase + 8))); /* set for PIO pseudo DMA */ |
314 | outb(0, qbase + 0xb)((__builtin_constant_p((qbase + 0xb)) && (qbase + 0xb ) < 256) ? __outbc((0),(qbase + 0xb)) : __outb((0),(qbase + 0xb))); /* disable ints */ |
315 | inb(qbase + 8)((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __inbc(qbase + 8) : __inb(qbase + 8)); /* clear int bits */ |
316 | REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))); |
317 | outb(0x40, qbase + 0xb)((__builtin_constant_p((qbase + 0xb)) && (qbase + 0xb ) < 256) ? __outbc((0x40),(qbase + 0xb)) : __outb((0x40),( qbase + 0xb))); /* enable features */ |
318 | |
319 | /* configurables */ |
320 | outb( qlcfgc , qbase + 0xc)((__builtin_constant_p((qbase + 0xc)) && (qbase + 0xc ) < 256) ? __outbc((qlcfgc),(qbase + 0xc)) : __outb((qlcfgc ),(qbase + 0xc))); |
321 | /* config: no reset interrupt, (initiator) bus id */ |
322 | outb( 0x40 | qlcfg8 | qinitid, qbase + 8)((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __outbc((0x40 | qlcfg8 | qinitid),(qbase + 8)) : __outb ((0x40 | qlcfg8 | qinitid),(qbase + 8))); |
323 | outb( qlcfg7 , qbase + 7 )((__builtin_constant_p((qbase + 7)) && (qbase + 7) < 256) ? __outbc((qlcfg7),(qbase + 7)) : __outb((qlcfg7),(qbase + 7))); |
324 | outb( qlcfg6 , qbase + 6 )((__builtin_constant_p((qbase + 6)) && (qbase + 6) < 256) ? __outbc((qlcfg6),(qbase + 6)) : __outb((qlcfg6),(qbase + 6))); |
325 | /**/ |
326 | outb(qlcfg5, qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __outbc((qlcfg5),(qbase + 5)) : __outb((qlcfg5),(qbase + 5))); /* select timer */ |
327 | outb(qlcfg9 & 7, qbase + 9)((__builtin_constant_p((qbase + 9)) && (qbase + 9) < 256) ? __outbc((qlcfg9 & 7),(qbase + 9)) : __outb((qlcfg9 & 7),(qbase + 9))); /* prescaler */ |
328 | /* outb(0x99, qbase + 5); */ |
329 | outb(cmd->target, qbase + 4)((__builtin_constant_p((qbase + 4)) && (qbase + 4) < 256) ? __outbc((cmd->target),(qbase + 4)) : __outb((cmd-> target),(qbase + 4))); |
330 | |
331 | for (i = 0; i < cmd->cmd_len; i++) |
332 | outb(cmd->cmnd[i], qbase + 2)((__builtin_constant_p((qbase + 2)) && (qbase + 2) < 256) ? __outbc((cmd->cmnd[i]),(qbase + 2)) : __outb((cmd-> cmnd[i]),(qbase + 2))); |
333 | qlcmd = cmd; |
334 | outb(0x41, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((0x41),(qbase + 3)) : __outb((0x41),(qbase + 3 ))); /* select and send command */ |
335 | restore_flags( flags )__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); |
336 | } |
337 | /*----------------------------------------------------------------*/ |
338 | /* process scsi command - usually after interrupt */ |
339 | static unsigned int ql_pcmd(Scsi_Cmnd * cmd) |
340 | { |
341 | unsigned int i, j, k; |
342 | unsigned int result; /* ultimate return result */ |
343 | unsigned int status; /* scsi returned status */ |
344 | unsigned int message; /* scsi returned message */ |
345 | unsigned int phase; /* recorded scsi phase */ |
346 | unsigned int reqlen; /* total length of transfer */ |
347 | struct scatterlist *sglist; /* scatter-gather list pointer */ |
348 | unsigned int sgcount; /* sg counter */ |
349 | |
350 | rtrc(1){} |
351 | j = inb(qbase + 6)((__builtin_constant_p((qbase + 6)) && (qbase + 6) < 256) ? __inbc(qbase + 6) : __inb(qbase + 6)); |
352 | i = inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5)); |
353 | if (i == 0x20) { |
354 | return (DID_NO_CONNECT0x01 << 16); |
355 | } |
356 | i |= inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5)); /* the 0x10 bit can be set after the 0x08 */ |
357 | if (i != 0x18) { |
358 | printk("Ql:Bad Interrupt status:%02x\n", i); |
359 | ql_zap(); |
360 | return (DID_BAD_INTR0x09 << 16); |
361 | } |
362 | j &= 7; /* j = inb( qbase + 7 ) >> 5; */ |
363 | /* correct status is supposed to be step 4 */ |
364 | /* it sometimes returns step 3 but with 0 bytes left to send */ |
365 | /* We can try stuffing the FIFO with the max each time, but we will get a |
366 | sequence of 3 if any bytes are left (but we do flush the FIFO anyway */ |
367 | if(j != 3 && j != 4) { |
368 | printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 )((__builtin_constant_p((qbase+7)) && (qbase+7) < 256 ) ? __inbc(qbase+7) : __inb(qbase+7)) & 0x1f ); |
369 | ql_zap(); |
370 | return (DID_ERROR0x07 << 16); |
371 | } |
372 | result = DID_OK0x00; |
373 | if (inb(qbase + 7)((__builtin_constant_p((qbase + 7)) && (qbase + 7) < 256) ? __inbc(qbase + 7) : __inb(qbase + 7)) & 0x1f) /* if some bytes in fifo */ |
374 | outb(1, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((1),(qbase + 3)) : __outb((1),(qbase + 3))); /* clear fifo */ |
375 | /* note that request_bufflen is the total xfer size when sg is used */ |
376 | reqlen = cmd->request_bufflen; |
377 | /* note that it won't work if transfers > 16M are requested */ |
378 | if (reqlen && !((phase = inb(qbase + 4)((__builtin_constant_p((qbase + 4)) && (qbase + 4) < 256) ? __inbc(qbase + 4) : __inb(qbase + 4))) & 6)) { /* data phase */ |
379 | rtrc(2){} |
380 | outb(reqlen, qbase)((__builtin_constant_p((qbase)) && (qbase) < 256) ? __outbc((reqlen),(qbase)) : __outb((reqlen),(qbase))); /* low-mid xfer cnt */ |
381 | outb(reqlen >> 8, qbase+1)((__builtin_constant_p((qbase+1)) && (qbase+1) < 256 ) ? __outbc((reqlen >> 8),(qbase+1)) : __outb((reqlen >> 8),(qbase+1))); /* low-mid xfer cnt */ |
382 | outb(reqlen >> 16, qbase + 0xe)((__builtin_constant_p((qbase + 0xe)) && (qbase + 0xe ) < 256) ? __outbc((reqlen >> 16),(qbase + 0xe)) : __outb ((reqlen >> 16),(qbase + 0xe))); /* high xfer cnt */ |
383 | outb(0x90, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((0x90),(qbase + 3)) : __outb((0x90),(qbase + 3 ))); /* command do xfer */ |
384 | /* PIO pseudo DMA to buffer or sglist */ |
385 | REG1( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd))), ((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc( (0xb4 | 2),(qbase + 0xd)) : __outb((0xb4 | 2),(qbase + 0xd))) ); |
386 | if (!cmd->use_sg) |
387 | ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen); |
388 | else { |
389 | sgcount = cmd->use_sg; |
390 | sglist = cmd->request_buffer; |
391 | while (sgcount--) { |
392 | if (qabort) { |
393 | REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))); |
394 | return ((qabort == 1 ? DID_ABORT0x05 : DID_RESET0x08) << 16); |
395 | } |
396 | if (ql_pdma(phase, sglist->address, sglist->length)) |
397 | break; |
398 | sglist++; |
399 | } |
400 | } |
401 | REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))); |
402 | rtrc(2){} |
403 | /* wait for irq (split into second state of irq handler if this can take time) */ |
404 | if ((k = ql_wai())) |
405 | return (k << 16); |
406 | k = inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5)); /* should be 0x10, bus service */ |
Value stored to 'k' is never read | |
407 | } |
408 | /*** Enter Status (and Message In) Phase ***/ |
409 | k = jiffies + WATCHDOG5000000; |
410 | while ( k > jiffies && !qabort && !(inb(qbase + 4)((__builtin_constant_p((qbase + 4)) && (qbase + 4) < 256) ? __inbc(qbase + 4) : __inb(qbase + 4)) & 6)); /* wait for status phase */ |
411 | if ( k <= jiffies ) { |
412 | ql_zap(); |
413 | return (DID_TIME_OUT0x03 << 16); |
414 | } |
415 | while (inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5))); /* clear pending ints */ |
416 | if (qabort) |
417 | return ((qabort == 1 ? DID_ABORT0x05 : DID_RESET0x08) << 16); |
418 | outb(0x11, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((0x11),(qbase + 3)) : __outb((0x11),(qbase + 3 ))); /* get status and message */ |
419 | if ((k = ql_wai())) |
420 | return (k << 16); |
421 | i = inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5)); /* get chip irq stat */ |
422 | j = inb(qbase + 7)((__builtin_constant_p((qbase + 7)) && (qbase + 7) < 256) ? __inbc(qbase + 7) : __inb(qbase + 7)) & 0x1f; /* and bytes rec'd */ |
423 | status = inb(qbase + 2)((__builtin_constant_p((qbase + 2)) && (qbase + 2) < 256) ? __inbc(qbase + 2) : __inb(qbase + 2)); |
424 | message = inb(qbase + 2)((__builtin_constant_p((qbase + 2)) && (qbase + 2) < 256) ? __inbc(qbase + 2) : __inb(qbase + 2)); |
425 | /* should get function complete int if Status and message, else bus serv if only status */ |
426 | if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) { |
427 | printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j); |
428 | result = DID_ERROR0x07; |
429 | } |
430 | outb(0x12, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((0x12),(qbase + 3)) : __outb((0x12),(qbase + 3 ))); /* done, disconnect */ |
431 | rtrc(1){} |
432 | if ((k = ql_wai())) |
433 | return (k << 16); |
434 | /* should get bus service interrupt and disconnect interrupt */ |
435 | i = inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5)); /* should be bus service */ |
436 | while (!qabort && ((i & 0x20) != 0x20)) { |
437 | barrier()__asm__ __volatile__("": : :"memory"); |
438 | i |= inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5)); |
439 | } |
440 | rtrc(0){} |
441 | if (qabort) |
442 | return ((qabort == 1 ? DID_ABORT0x05 : DID_RESET0x08) << 16); |
443 | return (result << 16) | (message << 8) | (status & STATUS_MASK0x3e); |
444 | } |
445 | |
446 | #if QL_USE_IRQ1 |
447 | /*----------------------------------------------------------------*/ |
448 | /* interrupt handler */ |
449 | static void ql_ihandl(int irq, void *dev_id, struct pt_regs * regs) |
450 | { |
451 | Scsi_Cmnd *icmd; |
452 | REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))); |
453 | if (!(inb(qbase + 4)((__builtin_constant_p((qbase + 4)) && (qbase + 4) < 256) ? __inbc(qbase + 4) : __inb(qbase + 4)) & 0x80)) /* false alarm? */ |
454 | return; |
455 | if (qlcmd == NULL((void *) 0)) { /* no command to process? */ |
456 | int i; |
457 | i = 16; |
458 | while (i-- && inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5))); /* maybe also ql_zap() */ |
459 | return; |
460 | } |
461 | icmd = qlcmd; |
462 | icmd->result = ql_pcmd(icmd); |
463 | qlcmd = NULL((void *) 0); |
464 | /* if result is CHECK CONDITION done calls qcommand to request sense */ |
465 | (icmd->scsi_done) (icmd); |
466 | } |
467 | #endif |
468 | |
469 | /*----------------------------------------------------------------*/ |
470 | /* global functions */ |
471 | /*----------------------------------------------------------------*/ |
472 | /* non queued command */ |
473 | #if QL_USE_IRQ1 |
474 | static void qlidone(Scsi_Cmnd * cmd) {}; /* null function */ |
475 | #endif |
476 | |
477 | /* command process */ |
478 | int qlogicfas_command(Scsi_Cmnd * cmd) |
479 | { |
480 | int k; |
481 | #if QL_USE_IRQ1 |
482 | if (qlirq >= 0) { |
483 | qlogicfas_queuecommand(cmd, qlidone); |
484 | while (qlcmd != NULL((void *) 0)); |
485 | return cmd->result; |
486 | } |
487 | #endif |
488 | /* non-irq version */ |
489 | if (cmd->target == qinitid) |
490 | return (DID_BAD_TARGET0x04 << 16); |
491 | ql_icmd(cmd); |
492 | if ((k = ql_wai())) |
493 | return (k << 16); |
494 | return ql_pcmd(cmd); |
495 | |
496 | } |
497 | |
498 | #if QL_USE_IRQ1 |
499 | /*----------------------------------------------------------------*/ |
500 | /* queued command */ |
501 | int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) |
502 | { |
503 | if(cmd->target == qinitid) { |
504 | cmd->result = DID_BAD_TARGET0x04 << 16; |
505 | done(cmd); |
506 | return 0; |
507 | } |
508 | |
509 | cmd->scsi_done = done; |
510 | /* wait for the last command's interrupt to finish */ |
511 | while (qlcmd != NULL((void *) 0)) |
512 | barrier()__asm__ __volatile__("": : :"memory"); |
513 | ql_icmd(cmd); |
514 | return 0; |
515 | } |
516 | #else |
517 | int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) |
518 | { |
519 | return 1; |
520 | } |
521 | #endif |
522 | |
523 | #ifdef PCMCIA |
524 | /*----------------------------------------------------------------*/ |
525 | /* allow PCMCIA code to preset the port */ |
526 | /* port should be 0 and irq to -1 respectively for autoprobing */ |
527 | void qlogicfas_preset(int port, int irq) |
528 | { |
529 | qbase=port; |
530 | qlirq=irq; |
531 | } |
532 | #endif |
533 | |
534 | /*----------------------------------------------------------------*/ |
535 | /* look for qlogic card and init if found */ |
536 | int qlogicfas_detect(Scsi_Host_Template * host) |
537 | { |
538 | int i, j; /* these are only used by IRQ detect */ |
539 | int qltyp; /* type of chip */ |
540 | struct Scsi_Host *hreg; /* registered host structure */ |
541 | unsigned long flags; |
542 | |
543 | host->proc_dir = &proc_scsi_qlogicfas; |
544 | |
545 | /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the |
546 | address - I check 230 first since MIDI cards are typically at 330 |
547 | |
548 | Theoretically, two Qlogic cards can coexist in the same system. This |
549 | should work by simply using this as a loadable module for the second |
550 | card, but I haven't tested this. |
551 | */ |
552 | |
553 | if( !qbase ) { |
554 | for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { |
555 | if( check_region( qbase , 0x10 ) ) |
556 | continue; |
557 | REG1( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd))), ((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc( (0xb4 | 2),(qbase + 0xd)) : __outb((0xb4 | 2),(qbase + 0xd))) ); |
558 | if ( ( (inb(qbase + 0xe)((__builtin_constant_p((qbase + 0xe)) && (qbase + 0xe ) < 256) ? __inbc(qbase + 0xe) : __inb(qbase + 0xe)) ^ inb(qbase + 0xe)((__builtin_constant_p((qbase + 0xe)) && (qbase + 0xe ) < 256) ? __inbc(qbase + 0xe) : __inb(qbase + 0xe))) == 7 ) |
559 | && ( (inb(qbase + 0xe)((__builtin_constant_p((qbase + 0xe)) && (qbase + 0xe ) < 256) ? __inbc(qbase + 0xe) : __inb(qbase + 0xe)) ^ inb(qbase + 0xe)((__builtin_constant_p((qbase + 0xe)) && (qbase + 0xe ) < 256) ? __inbc(qbase + 0xe) : __inb(qbase + 0xe))) == 7 ) ) |
560 | break; |
561 | } |
562 | if (qbase == 0x430) |
563 | return 0; |
564 | } |
565 | else |
566 | printk( "Ql: Using preset base address of %03x\n", qbase ); |
567 | |
568 | qltyp = inb(qbase + 0xe)((__builtin_constant_p((qbase + 0xe)) && (qbase + 0xe ) < 256) ? __inbc(qbase + 0xe) : __inb(qbase + 0xe)) & 0xf8; |
569 | qinitid = host->this_id; |
570 | if (qinitid < 0) |
571 | qinitid = 7; /* if no ID, use 7 */ |
572 | outb(1, qbase + 8)((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __outbc((1),(qbase + 8)) : __outb((1),(qbase + 8))); /* set for PIO pseudo DMA */ |
573 | REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))); |
574 | outb(0x40 | qlcfg8 | qinitid, qbase + 8)((__builtin_constant_p((qbase + 8)) && (qbase + 8) < 256) ? __outbc((0x40 | qlcfg8 | qinitid),(qbase + 8)) : __outb ((0x40 | qlcfg8 | qinitid),(qbase + 8))); /* (ini) bus id, disable scsi rst */ |
575 | outb(qlcfg5, qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __outbc((qlcfg5),(qbase + 5)) : __outb((qlcfg5),(qbase + 5))); /* select timer */ |
576 | outb(qlcfg9, qbase + 9)((__builtin_constant_p((qbase + 9)) && (qbase + 9) < 256) ? __outbc((qlcfg9),(qbase + 9)) : __outb((qlcfg9),(qbase + 9))); /* prescaler */ |
577 | #if QL_RESET_AT_START0 |
578 | outb( 3 , qbase + 3 )((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((3),(qbase + 3)) : __outb((3),(qbase + 3))); |
579 | REG1( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd))), ((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc( (0xb4 | 2),(qbase + 0xd)) : __outb((0xb4 | 2),(qbase + 0xd))) ); |
580 | while( inb( qbase + 0xf )((__builtin_constant_p((qbase + 0xf)) && (qbase + 0xf ) < 256) ? __inbc(qbase + 0xf) : __inb(qbase + 0xf)) & 4 ); |
581 | REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))); |
582 | #endif |
583 | #if QL_USE_IRQ1 |
584 | /* IRQ probe - toggle pin and check request pending */ |
585 | |
586 | if( qlirq == -1 ) { |
587 | save_flags( flags )__asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); |
588 | cli()__asm__ __volatile__ ("cli": : :"memory"); |
589 | i = 0xffff; |
590 | j = 3; |
591 | outb(0x90, qbase + 3)((__builtin_constant_p((qbase + 3)) && (qbase + 3) < 256) ? __outbc((0x90),(qbase + 3)) : __outb((0x90),(qbase + 3 ))); /* illegal command - cause interrupt */ |
592 | REG1( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) | 0x80),(qbase + 0xd))), ((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc( (0xb4 | 2),(qbase + 0xd)) : __outb((0xb4 | 2),(qbase + 0xd))) ); |
593 | outb(10, 0x20)((__builtin_constant_p((0x20)) && (0x20) < 256) ? __outbc ((10),(0x20)) : __outb((10),(0x20))); /* access pending interrupt map */ |
594 | outb(10, 0xa0)((__builtin_constant_p((0xa0)) && (0xa0) < 256) ? __outbc ((10),(0xa0)) : __outb((10),(0xa0))); |
595 | while (j--) { |
596 | outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd)((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((0xb0 | 2),(qbase + 0xd)) : __outb((0xb0 | 2),(qbase + 0xd))); /* int pin off */ |
597 | i &= ~(inb(0x20)((__builtin_constant_p((0x20)) && (0x20) < 256) ? __inbc (0x20) : __inb(0x20)) | (inb(0xa0)((__builtin_constant_p((0xa0)) && (0xa0) < 256) ? __inbc (0xa0) : __inb(0xa0)) << 8)); /* find IRQ off */ |
598 | outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd)((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((0xb4 | 2),(qbase + 0xd)) : __outb((0xb4 | 2),(qbase + 0xd))); /* int pin on */ |
599 | i &= inb(0x20)((__builtin_constant_p((0x20)) && (0x20) < 256) ? __inbc (0x20) : __inb(0x20)) | (inb(0xa0)((__builtin_constant_p((0xa0)) && (0xa0) < 256) ? __inbc (0xa0) : __inb(0xa0)) << 8); /* find IRQ on */ |
600 | } |
601 | REG0( ((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd ) < 256) ? __outbc((((__builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd)) : __outb((((__builtin_constant_p ((qbase + 0xd)) && (qbase + 0xd) < 256) ? __inbc(qbase + 0xd) : __inb(qbase + 0xd)) & 0x7f),(qbase + 0xd))), (( __builtin_constant_p((qbase + 0xd)) && (qbase + 0xd) < 256) ? __outbc((4),(qbase + 0xd)) : __outb((4),(qbase + 0xd) ))); |
602 | while (inb(qbase + 5)((__builtin_constant_p((qbase + 5)) && (qbase + 5) < 256) ? __inbc(qbase + 5) : __inb(qbase + 5))); /* purge int */ |
603 | j = -1; |
604 | while (i) /* find on bit */ |
605 | i >>= 1, j++; /* should check for exactly 1 on */ |
606 | qlirq = j; |
607 | restore_flags( flags )__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); |
608 | } |
609 | else |
610 | printk( "Ql: Using preset IRQ %d\n", qlirq ); |
611 | |
612 | if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogicfas", NULL((void *) 0))) |
613 | host->can_queue = 1; |
614 | #endif |
615 | request_region( qbase , 0x10 ,"qlogicfas"); |
616 | hreg = scsi_register( host , 0 ); /* no host data */ |
617 | hreg->io_port = qbase; |
618 | hreg->n_io_port = 16; |
619 | hreg->dma_channel = -1; |
620 | if( qlirq != -1 ) |
621 | hreg->irq = qlirq; |
622 | |
623 | sprintflinux_sprintf(qinfo, "Qlogicfas Driver version 0.45, chip %02X at %03X, IRQ %d, TPdma:%d", |
624 | qltyp, qbase, qlirq, QL_TURBO_PDMA1 ); |
625 | host->name = qinfo; |
626 | |
627 | return 1; |
628 | } |
629 | |
630 | /*----------------------------------------------------------------*/ |
631 | /* return bios parameters */ |
632 | int qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[]) |
633 | { |
634 | /* This should mimic the DOS Qlogic driver's behavior exactly */ |
635 | ip[0] = 0x40; |
636 | ip[1] = 0x20; |
637 | ip[2] = disk->capacity / (ip[0] * ip[1]); |
638 | if (ip[2] > 1024) { |
639 | ip[0] = 0xff; |
640 | ip[1] = 0x3f; |
641 | ip[2] = disk->capacity / (ip[0] * ip[1]); |
642 | if (ip[2] > 1023) |
643 | ip[2] = 1023; |
644 | } |
645 | return 0; |
646 | } |
647 | |
648 | /*----------------------------------------------------------------*/ |
649 | /* abort command in progress */ |
650 | int qlogicfas_abort(Scsi_Cmnd * cmd) |
651 | { |
652 | qabort = 1; |
653 | ql_zap(); |
654 | return 0; |
655 | } |
656 | |
657 | /*----------------------------------------------------------------*/ |
658 | /* reset SCSI bus */ |
659 | int qlogicfas_reset(Scsi_Cmnd * cmd, unsigned int flags) |
660 | { |
661 | qabort = 2; |
662 | ql_zap(); |
663 | return 1; |
664 | } |
665 | |
666 | /*----------------------------------------------------------------*/ |
667 | /* return info string */ |
668 | const char *qlogicfas_info(struct Scsi_Host * host) |
669 | { |
670 | return qinfo; |
671 | } |
672 | |
673 | #ifdef MODULE |
674 | /* Eventually this will go into an include file, but this will be later */ |
675 | Scsi_Host_Template driver_template = QLOGICFAS{ ((void *) 0), ((void *) 0), ((void *) 0), ((void *) 0), ((void *) 0), qlogicfas_detect, ((void *) 0), qlogicfas_info, qlogicfas_command , qlogicfas_queuecommand, qlogicfas_abort, qlogicfas_reset, ( (void *) 0), qlogicfas_biosparam, 0, -1, 0xff, 1, 0, 0, 0 }; |
676 | |
677 | #include "scsi_module.c" |
678 | #endif |
679 |