File: | obj-scan-build/../linux/src/drivers/scsi/u14-34f.c |
Location: | line 763, column 10 |
Description: | Array subscript is undefined |
1 | /* | |||
2 | * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. | |||
3 | * | |||
4 | * 26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111 | |||
5 | * Added command line option (et:[y|n]) to use the existing | |||
6 | * translation (returned by scsicam_bios_param) as disk geometry. | |||
7 | * The default is et:n, which uses the disk geometry jumpered | |||
8 | * on the board. | |||
9 | * The default value et:n is compatible with all previous revisions | |||
10 | * of this driver. | |||
11 | * | |||
12 | * 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104 | |||
13 | * Increased busy timeout from 10 msec. to 200 msec. while | |||
14 | * processing interrupts. | |||
15 | * | |||
16 | * 18 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102 | |||
17 | * Improved abort handling during the eh recovery process. | |||
18 | * | |||
19 | * 13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101 | |||
20 | * The driver is now fully SMP safe, including the | |||
21 | * abort and reset routines. | |||
22 | * Added command line options (eh:[y|n]) to choose between | |||
23 | * new_eh_code and the old scsi code. | |||
24 | * If linux version >= 2.1.101 the default is eh:y, while the eh | |||
25 | * option is ignored for previous releases and the old scsi code | |||
26 | * is used. | |||
27 | * | |||
28 | * 18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97 | |||
29 | * Reworked interrupt handler. | |||
30 | * | |||
31 | * 11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95 | |||
32 | * Major reliability improvement: when a batch with overlapping | |||
33 | * requests is detected, requests are queued one at a time | |||
34 | * eliminating any possible board or drive reordering. | |||
35 | * | |||
36 | * 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95 | |||
37 | * Improved SMP support (if linux version >= 2.1.95). | |||
38 | * | |||
39 | * 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94 | |||
40 | * Performance improvement: when sequential i/o is detected, | |||
41 | * always use direct sort instead of reverse sort. | |||
42 | * | |||
43 | * 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92 | |||
44 | * io_port is now unsigned long. | |||
45 | * | |||
46 | * 17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88 | |||
47 | * Use new scsi error handling code (if linux version >= 2.1.88). | |||
48 | * Use new interrupt code. | |||
49 | * | |||
50 | * 12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55 | |||
51 | * Use of udelay inside the wait loops to avoid timeout | |||
52 | * problems with fast cpus. | |||
53 | * Removed check about useless calls to the interrupt service | |||
54 | * routine (reported on SMP systems only). | |||
55 | * At initialization time "sorted/unsorted" is displayed instead | |||
56 | * of "linked/unlinked" to reinforce the fact that "linking" is | |||
57 | * nothing but "elevator sorting" in the actual implementation. | |||
58 | * | |||
59 | * 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38 | |||
60 | * Use of serial_number_at_timeout in abort and reset processing. | |||
61 | * Use of the __initfunc and __initdata macro in setup code. | |||
62 | * Minor cleanups in the list_statistics code. | |||
63 | * | |||
64 | * 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26 | |||
65 | * When loading as a module, parameter passing is now supported | |||
66 | * both in 2.0 and in 2.1 style. | |||
67 | * Fixed data transfer direction for some SCSI opcodes. | |||
68 | * Immediate acknowledge to request sense commands. | |||
69 | * Linked commands to each disk device are now reordered by elevator | |||
70 | * sorting. Rare cases in which reordering of write requests could | |||
71 | * cause wrong results are managed. | |||
72 | * | |||
73 | * 18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28 | |||
74 | * Added command line options to enable/disable linked commands | |||
75 | * (lc:[y|n]), old firmware support (of:[y|n]) and to set the max | |||
76 | * queue depth (mq:xx). Default is "u14-34f=lc:n,of:n,mq:8". | |||
77 | * Improved command linking. | |||
78 | * | |||
79 | * 8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27 | |||
80 | * Added linked command support. | |||
81 | * | |||
82 | * 3 Dec 1996 rev. 2.40 for linux 2.1.14 and 2.0.27 | |||
83 | * Added queue depth adjustment. | |||
84 | * | |||
85 | * 22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26 | |||
86 | * The list of i/o ports to be probed can be overwritten by the | |||
87 | * "u14-34f=port0,port1,...." boot command line option. | |||
88 | * Scatter/gather lists are now allocated by a number of kmalloc | |||
89 | * calls, in order to avoid the previous size limit of 64Kb. | |||
90 | * | |||
91 | * 16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25 | |||
92 | * Added multichannel support. | |||
93 | * | |||
94 | * 27 Sep 1996 rev. 2.12 for linux 2.1.0 | |||
95 | * Portability cleanups (virtual/bus addressing, little/big endian | |||
96 | * support). | |||
97 | * | |||
98 | * 09 Jul 1996 rev. 2.11 for linux 2.0.4 | |||
99 | * "Data over/under-run" no longer implies a redo on all targets. | |||
100 | * Number of internal retries is now limited. | |||
101 | * | |||
102 | * 16 Apr 1996 rev. 2.10 for linux 1.3.90 | |||
103 | * New argument "reset_flags" to the reset routine. | |||
104 | * | |||
105 | * 21 Jul 1995 rev. 2.02 for linux 1.3.11 | |||
106 | * Fixed Data Transfer Direction for some SCSI commands. | |||
107 | * | |||
108 | * 13 Jun 1995 rev. 2.01 for linux 1.2.10 | |||
109 | * HAVE_OLD_UX4F_FIRMWARE should be defined for U34F boards when | |||
110 | * the firmware prom is not the latest one (28008-006). | |||
111 | * | |||
112 | * 11 Mar 1995 rev. 2.00 for linux 1.2.0 | |||
113 | * Fixed a bug which prevented media change detection for removable | |||
114 | * disk drives. | |||
115 | * | |||
116 | * 23 Feb 1995 rev. 1.18 for linux 1.1.94 | |||
117 | * Added a check for scsi_register returning NULL. | |||
118 | * | |||
119 | * 11 Feb 1995 rev. 1.17 for linux 1.1.91 | |||
120 | * U14F qualified to run with 32 sglists. | |||
121 | * Now DEBUG_RESET is disabled by default. | |||
122 | * | |||
123 | * 9 Feb 1995 rev. 1.16 for linux 1.1.90 | |||
124 | * Use host->wish_block instead of host->block. | |||
125 | * | |||
126 | * 8 Feb 1995 rev. 1.15 for linux 1.1.89 | |||
127 | * Cleared target_time_out counter while performing a reset. | |||
128 | * | |||
129 | * 28 Jan 1995 rev. 1.14 for linux 1.1.86 | |||
130 | * Added module support. | |||
131 | * Log and do a retry when a disk drive returns a target status | |||
132 | * different from zero on a recovered error. | |||
133 | * Auto detects if U14F boards have an old firmware revision. | |||
134 | * Max number of scatter/gather lists set to 16 for all boards | |||
135 | * (most installation run fine using 33 sglists, while other | |||
136 | * has problems when using more then 16). | |||
137 | * | |||
138 | * 16 Jan 1995 rev. 1.13 for linux 1.1.81 | |||
139 | * Display a message if check_region detects a port address | |||
140 | * already in use. | |||
141 | * | |||
142 | * 15 Dec 1994 rev. 1.12 for linux 1.1.74 | |||
143 | * The host->block flag is set for all the detected ISA boards. | |||
144 | * | |||
145 | * 30 Nov 1994 rev. 1.11 for linux 1.1.68 | |||
146 | * Redo i/o on target status CHECK_CONDITION for TYPE_DISK only. | |||
147 | * Added optional support for using a single board at a time. | |||
148 | * | |||
149 | * 14 Nov 1994 rev. 1.10 for linux 1.1.63 | |||
150 | * | |||
151 | * 28 Oct 1994 rev. 1.09 for linux 1.1.58 Final BETA release. | |||
152 | * 16 Jul 1994 rev. 1.00 for linux 1.1.29 Initial ALPHA release. | |||
153 | * | |||
154 | * This driver is a total replacement of the original UltraStor | |||
155 | * scsi driver, but it supports ONLY the 14F and 34F boards. | |||
156 | * It can be configured in the same kernel in which the original | |||
157 | * ultrastor driver is configured to allow the original U24F | |||
158 | * support. | |||
159 | * | |||
160 | * Multiple U14F and/or U34F host adapters are supported. | |||
161 | * | |||
162 | * Copyright (C) 1994-1998 Dario Ballabio (dario@milano.europe.dg.com) | |||
163 | * | |||
164 | * Redistribution and use in source and binary forms, with or without | |||
165 | * modification, are permitted provided that redistributions of source | |||
166 | * code retain the above copyright notice and this comment without | |||
167 | * modification. | |||
168 | * | |||
169 | * WARNING: if your 14/34F board has an old firmware revision (see below) | |||
170 | * you must change "#undef" into "#define" in the following | |||
171 | * statement. | |||
172 | */ | |||
173 | #undef HAVE_OLD_UX4F_FIRMWARE | |||
174 | /* | |||
175 | * The UltraStor 14F, 24F, and 34F are a family of intelligent, high | |||
176 | * performance SCSI-2 host adapters. | |||
177 | * Here is the scoop on the various models: | |||
178 | * | |||
179 | * 14F - ISA first-party DMA HA with floppy support and WD1003 emulation. | |||
180 | * 24F - EISA Bus Master HA with floppy support and WD1003 emulation. | |||
181 | * 34F - VESA Local-Bus Bus Master HA (no WD1003 emulation). | |||
182 | * | |||
183 | * This code has been tested with up to two U14F boards, using both | |||
184 | * firmware 28004-005/38004-004 (BIOS rev. 2.00) and the latest firmware | |||
185 | * 28004-006/38004-005 (BIOS rev. 2.01). | |||
186 | * | |||
187 | * The latest firmware is required in order to get reliable operations when | |||
188 | * clustering is enabled. ENABLE_CLUSTERING provides a performance increase | |||
189 | * up to 50% on sequential access. | |||
190 | * | |||
191 | * Since the Scsi_Host_Template structure is shared among all 14F and 34F, | |||
192 | * the last setting of use_clustering is in effect for all of these boards. | |||
193 | * | |||
194 | * Here a sample configuration using two U14F boards: | |||
195 | * | |||
196 | U14F0: ISA 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, MB 16, of:n, lc:y, mq:8. | |||
197 | U14F1: ISA 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, MB 16, of:n, lc:y, mq:8. | |||
198 | * | |||
199 | * The boot controller must have its BIOS enabled, while other boards can | |||
200 | * have their BIOS disabled, or enabled to an higher address. | |||
201 | * Boards are named Ux4F0, Ux4F1..., according to the port address order in | |||
202 | * the io_port[] array. | |||
203 | * | |||
204 | * The following facts are based on real testing results (not on | |||
205 | * documentation) on the above U14F board. | |||
206 | * | |||
207 | * - The U14F board should be jumpered for bus on time less or equal to 7 | |||
208 | * microseconds, while the default is 11 microseconds. This is order to | |||
209 | * get acceptable performance while using floppy drive and hard disk | |||
210 | * together. The jumpering for 7 microseconds is: JP13 pin 15-16, | |||
211 | * JP14 pin 7-8 and pin 9-10. | |||
212 | * The reduction has a little impact on scsi performance. | |||
213 | * | |||
214 | * - If scsi bus length exceeds 3m., the scsi bus speed needs to be reduced | |||
215 | * from 10Mhz to 5Mhz (do this by inserting a jumper on JP13 pin 7-8). | |||
216 | * | |||
217 | * - If U14F on board firmware is older than 28004-006/38004-005, | |||
218 | * the U14F board is unable to provide reliable operations if the scsi | |||
219 | * request length exceeds 16Kbyte. When this length is exceeded the | |||
220 | * behavior is: | |||
221 | * - adapter_status equal 0x96 or 0xa3 or 0x93 or 0x94; | |||
222 | * - adapter_status equal 0 and target_status equal 2 on for all targets | |||
223 | * in the next operation following the reset. | |||
224 | * This sequence takes a long time (>3 seconds), so in the meantime | |||
225 | * the SD_TIMEOUT in sd.c could expire giving rise to scsi aborts | |||
226 | * (SD_TIMEOUT has been increased from 3 to 6 seconds in 1.1.31). | |||
227 | * Because of this I had to DISABLE_CLUSTERING and to work around the | |||
228 | * bus reset in the interrupt service routine, returning DID_BUS_BUSY | |||
229 | * so that the operations are retried without complains from the scsi.c | |||
230 | * code. | |||
231 | * Any reset of the scsi bus is going to kill tape operations, since | |||
232 | * no retry is allowed for tapes. Bus resets are more likely when the | |||
233 | * scsi bus is under heavy load. | |||
234 | * Requests using scatter/gather have a maximum length of 16 x 1024 bytes | |||
235 | * when DISABLE_CLUSTERING is in effect, but unscattered requests could be | |||
236 | * larger than 16Kbyte. | |||
237 | * | |||
238 | * The new firmware has fixed all the above problems. | |||
239 | * | |||
240 | * For U34F boards the latest bios prom is 38008-002 (BIOS rev. 2.01), | |||
241 | * the latest firmware prom is 28008-006. Older firmware 28008-005 has | |||
242 | * problems when using more then 16 scatter/gather lists. | |||
243 | * | |||
244 | * The list of i/o ports to be probed can be totally replaced by the | |||
245 | * boot command line option: "u14-34f=port0,port1,port2,...", where the | |||
246 | * port0, port1... arguments are ISA/VESA addresses to be probed. | |||
247 | * For example using "u14-34f=0x230,0x340", the driver probes only the two | |||
248 | * addresses 0x230 and 0x340 in this order; "u14-34f=0" totally disables | |||
249 | * this driver. | |||
250 | * | |||
251 | * After the optional list of detection probes, other possible command line | |||
252 | * options are: | |||
253 | * | |||
254 | * eh:y use new scsi code (linux 2.2 only); | |||
255 | * eh:n use old scsi code; | |||
256 | * et:y use disk geometry returned by scsicam_bios_param; | |||
257 | * et:n use disk geometry jumpered on the board; | |||
258 | * lc:y enables linked commands; | |||
259 | * lc:n disables linked commands; | |||
260 | * of:y enables old firmware support; | |||
261 | * of:n disables old firmware support; | |||
262 | * mq:xx set the max queue depth to the value xx (2 <= xx <= 8). | |||
263 | * | |||
264 | * The default value is: "u14-34f=lc:n,of:n,mq:8,et:n". | |||
265 | * An example using the list of detection probes could be: | |||
266 | * "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n,et:n". | |||
267 | * | |||
268 | * When loading as a module, parameters can be specified as well. | |||
269 | * The above example would be (use 1 in place of y and 0 in place of n): | |||
270 | * | |||
271 | * modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \ | |||
272 | * max_queue_depth=4 use_new_eh_code=0 ext_tran=0 | |||
273 | * | |||
274 | * ---------------------------------------------------------------------------- | |||
275 | * In this implementation, linked commands are designed to work with any DISK | |||
276 | * or CD-ROM, since this linking has only the intent of clustering (time-wise) | |||
277 | * and reordering by elevator sorting commands directed to each device, | |||
278 | * without any relation with the actual SCSI protocol between the controller | |||
279 | * and the device. | |||
280 | * If Q is the queue depth reported at boot time for each device (also named | |||
281 | * cmds/lun) and Q > 2, whenever there is already an active command to the | |||
282 | * device all other commands to the same device (up to Q-1) are kept waiting | |||
283 | * in the elevator sorting queue. When the active command completes, the | |||
284 | * commands in this queue are sorted by sector address. The sort is chosen | |||
285 | * between increasing or decreasing by minimizing the seek distance between | |||
286 | * the sector of the commands just completed and the sector of the first | |||
287 | * command in the list to be sorted. | |||
288 | * Trivial math assures that the unsorted average seek distance when doing | |||
289 | * random seeks over S sectors is S/3. | |||
290 | * When (Q-1) requests are uniformly distributed over S sectors, the average | |||
291 | * distance between two adjacent requests is S/((Q-1) + 1), so the sorted | |||
292 | * average seek distance for (Q-1) random requests over S sectors is S/Q. | |||
293 | * The elevator sorting hence divides the seek distance by a factor Q/3. | |||
294 | * The above pure geometric remarks are valid in all cases and the | |||
295 | * driver effectively reduces the seek distance by the predicted factor | |||
296 | * when there are Q concurrent read i/o operations on the device, but this | |||
297 | * does not necessarily results in a noticeable performance improvement: | |||
298 | * your mileage may vary.... | |||
299 | * | |||
300 | * Note: command reordering inside a batch of queued commands could cause | |||
301 | * wrong results only if there is at least one write request and the | |||
302 | * intersection (sector-wise) of all requests is not empty. | |||
303 | * When the driver detects a batch including overlapping requests | |||
304 | * (a really rare event) strict serial (pid) order is enforced. | |||
305 | * ---------------------------------------------------------------------------- | |||
306 | * | |||
307 | * The boards are named Ux4F0, Ux4F1,... according to the detection order. | |||
308 | * | |||
309 | * In order to support multiple ISA boards in a reliable way, | |||
310 | * the driver sets host->wish_block = TRUE for all ISA boards. | |||
311 | */ | |||
312 | ||||
313 | #include <linux/version.h> | |||
314 | ||||
315 | #define LinuxVersionCode(v, p, s)(((v)<<16)+((p)<<8)+(s)) (((v)<<16)+((p)<<8)+(s)) | |||
316 | #define MAX_INT_PARAM10 10 | |||
317 | ||||
318 | #if defined(MODULE) | |||
319 | #include <linux/module.h> | |||
320 | ||||
321 | #if LINUX_VERSION_CODE131108 >= LinuxVersionCode(2,1,26)(((2)<<16)+((1)<<8)+(26)) | |||
322 | MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM10) "i"); | |||
323 | MODULE_PARM(linked_comm, "i"); | |||
324 | MODULE_PARM(have_old_firmware, "i"); | |||
325 | MODULE_PARM(link_statistics, "i"); | |||
326 | MODULE_PARM(max_queue_depth, "i"); | |||
327 | MODULE_PARM(use_new_eh_code, "i"); | |||
328 | MODULE_PARM(ext_tran, "i"); | |||
329 | MODULE_AUTHOR("Dario Ballabio"); | |||
330 | #endif | |||
331 | ||||
332 | #endif | |||
333 | ||||
334 | #include <linux/string.h> | |||
335 | #include <linux/sched.h> | |||
336 | #include <linux/kernel.h> | |||
337 | #include <linux/ioport.h> | |||
338 | #include <linux/delay.h> | |||
339 | #include <asm/io.h> | |||
340 | #include <asm/system.h> | |||
341 | #include <asm/byteorder.h> | |||
342 | #include <linux/proc_fs.h> | |||
343 | #include <linux/blk.h> | |||
344 | #include "scsi.h" | |||
345 | #include "hosts.h" | |||
346 | #include "sd.h" | |||
347 | #include <asm/dma.h> | |||
348 | #include <asm/irq.h> | |||
349 | #include "u14-34f.h" | |||
350 | #include <linux/stat.h> | |||
351 | #include <linux/config.h> | |||
352 | ||||
353 | #if LINUX_VERSION_CODE131108 >= LinuxVersionCode(2,1,36)(((2)<<16)+((1)<<8)+(36)) | |||
354 | #include <linux/init.h> | |||
355 | #else | |||
356 | #define __initfunc(A)A A | |||
357 | #define __initdata | |||
358 | #define __init | |||
359 | #endif | |||
360 | ||||
361 | #if LINUX_VERSION_CODE131108 >= LinuxVersionCode(2,1,101)(((2)<<16)+((1)<<8)+(101)) | |||
362 | #include <asm/spinlock.h> | |||
363 | #define IRQ_FLAGSunsigned long irq_flags; | |||
364 | #define IRQ_LOCK__asm__ __volatile__ ("cli": : :"memory"); | |||
365 | #define IRQ_LOCK_SAVEdo {__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory"); __asm__ __volatile__ ("cli": : :"memory");} while (0); | |||
366 | #define IRQ_UNLOCK__asm__ __volatile__ ("sti": : :"memory"); | |||
367 | #define IRQ_UNLOCK_RESTOREdo {__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); | |||
368 | #define SPIN_FLAGS unsigned long spin_flags; | |||
369 | #define SPIN_LOCK spin_lock_irq(&io_request_lock); | |||
370 | #define SPIN_LOCK_SAVE spin_lock_irqsave(&io_request_lock, spin_flags); | |||
371 | #define SPIN_UNLOCK spin_unlock_irq(&io_request_lock); | |||
372 | #define SPIN_UNLOCK_RESTORE \ | |||
373 | spin_unlock_irqrestore(&io_request_lock, spin_flags); | |||
374 | static int use_new_eh_code = TRUE1; | |||
375 | #else | |||
376 | #define IRQ_FLAGSunsigned long irq_flags; unsigned long irq_flags; | |||
377 | #define IRQ_LOCK__asm__ __volatile__ ("cli": : :"memory"); cli()__asm__ __volatile__ ("cli": : :"memory"); | |||
378 | #define IRQ_LOCK_SAVEdo {__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory"); __asm__ __volatile__ ("cli": : :"memory");} while (0); do {save_flags(irq_flags)__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory" ); cli()__asm__ __volatile__ ("cli": : :"memory");} while (0); | |||
379 | #define IRQ_UNLOCK__asm__ __volatile__ ("sti": : :"memory"); sti()__asm__ __volatile__ ("sti": : :"memory"); | |||
380 | #define IRQ_UNLOCK_RESTOREdo {__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); do {restore_flags(irq_flags)__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); | |||
381 | #define SPIN_FLAGS | |||
382 | #define SPIN_LOCK | |||
383 | #define SPIN_LOCK_SAVE | |||
384 | #define SPIN_UNLOCK | |||
385 | #define SPIN_UNLOCK_RESTORE | |||
386 | static int use_new_eh_code = FALSE0; | |||
387 | #endif | |||
388 | ||||
389 | struct proc_dir_entry proc_scsi_u14_34f = { | |||
390 | PROC_SCSI_U14_34F, 6, "u14_34f", | |||
391 | S_IFDIR0040000 | S_IRUGO(00400|00040|00004) | S_IXUGO(00100|00010|00001), 2 | |||
392 | }; | |||
393 | ||||
394 | /* Values for the PRODUCT_ID ports for the 14/34F */ | |||
395 | #define PRODUCT_ID10x56 0x56 | |||
396 | #define PRODUCT_ID20x40 0x40 /* NOTE: Only upper nibble is used */ | |||
397 | ||||
398 | /* Subversion values */ | |||
399 | #define ISA0 0 | |||
400 | #define ESA1 1 | |||
401 | ||||
402 | #define OP_HOST_ADAPTER0x1 0x1 | |||
403 | #define OP_SCSI0x2 0x2 | |||
404 | #define OP_RESET0x4 0x4 | |||
405 | #define DTD_SCSI0x0 0x0 | |||
406 | #define DTD_IN0x1 0x1 | |||
407 | #define DTD_OUT0x2 0x2 | |||
408 | #define DTD_NONE0x3 0x3 | |||
409 | #define HA_CMD_INQUIRY0x1 0x1 | |||
410 | #define HA_CMD_SELF_DIAG0x2 0x2 | |||
411 | #define HA_CMD_READ_BUFF0x3 0x3 | |||
412 | #define HA_CMD_WRITE_BUFF0x4 0x4 | |||
413 | ||||
414 | #undef DEBUG_LINKED_COMMANDS | |||
415 | #undef DEBUG_DETECT | |||
416 | #undef DEBUG_INTERRUPT | |||
417 | #undef DEBUG_RESET | |||
418 | #undef DEBUG_GENERATE_ERRORS | |||
419 | #undef DEBUG_GENERATE_ABORTS | |||
420 | #undef DEBUG_GEOMETRY | |||
421 | ||||
422 | #define MAX_ISA3 3 | |||
423 | #define MAX_VESA1 1 | |||
424 | #define MAX_EISA0 0 | |||
425 | #define MAX_PCI0 0 | |||
426 | #define MAX_BOARDS(3 + 1 + 0 + 0) (MAX_ISA3 + MAX_VESA1 + MAX_EISA0 + MAX_PCI0) | |||
427 | #define MAX_CHANNEL1 1 | |||
428 | #define MAX_LUN8 8 | |||
429 | #define MAX_TARGET8 8 | |||
430 | #define MAX_MAILBOXES16 16 | |||
431 | #define MAX_SGLIST32 32 | |||
432 | #define MAX_SAFE_SGLIST16 16 | |||
433 | #define MAX_INTERNAL_RETRIES64 64 | |||
434 | #define MAX_CMD_PER_LUN2 2 | |||
435 | #define MAX_TAGGED_CMD_PER_LUN(16 - 2) (MAX_MAILBOXES16 - MAX_CMD_PER_LUN2) | |||
436 | ||||
437 | #define SKIP(~0UL) ULONG_MAX(~0UL) | |||
438 | #define FALSE0 0 | |||
439 | #define TRUE1 1 | |||
440 | #define FREE0 0 | |||
441 | #define IN_USE1 1 | |||
442 | #define LOCKED2 2 | |||
443 | #define IN_RESET3 3 | |||
444 | #define IGNORE4 4 | |||
445 | #define READY5 5 | |||
446 | #define ABORTING6 6 | |||
447 | #define NO_DMA0xff 0xff | |||
448 | #define MAXLOOP10000 10000 | |||
449 | ||||
450 | #define REG_LCL_MASK0 0 | |||
451 | #define REG_LCL_INTR1 1 | |||
452 | #define REG_SYS_MASK2 2 | |||
453 | #define REG_SYS_INTR3 3 | |||
454 | #define REG_PRODUCT_ID14 4 | |||
455 | #define REG_PRODUCT_ID25 5 | |||
456 | #define REG_CONFIG16 6 | |||
457 | #define REG_CONFIG27 7 | |||
458 | #define REG_OGM8 8 | |||
459 | #define REG_ICM12 12 | |||
460 | #define REGION_SIZE13 13 | |||
461 | #define BSY_ASSERTED0x01 0x01 | |||
462 | #define IRQ_ASSERTED0x01 0x01 | |||
463 | #define CMD_RESET0xc0 0xc0 | |||
464 | #define CMD_OGM_INTR0x01 0x01 | |||
465 | #define CMD_CLR_INTR0x01 0x01 | |||
466 | #define CMD_ENA_INTR0x81 0x81 | |||
467 | #define ASOK0x00 0x00 | |||
468 | #define ASST0x91 0x91 | |||
469 | ||||
470 | #define ARRAY_SIZE(arr)(sizeof (arr) / sizeof (arr)[0]) (sizeof (arr) / sizeof (arr)[0]) | |||
471 | #define YESNO(a)((a) ? 'y' : 'n') ((a) ? 'y' : 'n') | |||
472 | #define TLDEV(type)((type) == 0x00 || (type) == 0x05) ((type) == TYPE_DISK0x00 || (type) == TYPE_ROM0x05) | |||
473 | ||||
474 | #define PACKED__attribute__((packed)) __attribute__((packed)) | |||
475 | ||||
476 | struct sg_list { | |||
477 | unsigned int address; /* Segment Address */ | |||
478 | unsigned int num_bytes; /* Segment Length */ | |||
479 | }; | |||
480 | ||||
481 | /* MailBox SCSI Command Packet */ | |||
482 | struct mscp { | |||
483 | unsigned char opcode: 3; /* type of command */ | |||
484 | unsigned char xdir: 2; /* data transfer direction */ | |||
485 | unsigned char dcn: 1; /* disable disconnect */ | |||
486 | unsigned char ca: 1; /* use cache (if available) */ | |||
487 | unsigned char sg: 1; /* scatter/gather operation */ | |||
488 | unsigned char target: 3; /* SCSI target id */ | |||
489 | unsigned char channel: 2; /* SCSI channel number */ | |||
490 | unsigned char lun: 3; /* SCSI logical unit number */ | |||
491 | unsigned int data_address PACKED__attribute__((packed)); /* transfer data pointer */ | |||
492 | unsigned int data_len PACKED__attribute__((packed)); /* length in bytes */ | |||
493 | unsigned int link_address PACKED__attribute__((packed)); /* for linking command chains */ | |||
494 | unsigned char clink_id; /* identifies command in chain */ | |||
495 | unsigned char use_sg; /* (if sg is set) 8 bytes per list */ | |||
496 | unsigned char sense_len; | |||
497 | unsigned char scsi_cdbs_len; /* 6, 10, or 12 */ | |||
498 | unsigned char scsi_cdbs[12]; /* SCSI commands */ | |||
499 | unsigned char adapter_status; /* non-zero indicates HA error */ | |||
500 | unsigned char target_status; /* non-zero indicates target error */ | |||
501 | unsigned int sense_addr PACKED__attribute__((packed)); | |||
502 | Scsi_Cmnd *SCpnt; | |||
503 | unsigned int index; /* cp index */ | |||
504 | struct sg_list *sglist; | |||
505 | }; | |||
506 | ||||
507 | struct hostdata { | |||
508 | struct mscp cp[MAX_MAILBOXES16]; /* Mailboxes for this board */ | |||
509 | unsigned int cp_stat[MAX_MAILBOXES16]; /* FREE, IN_USE, LOCKED, IN_RESET */ | |||
510 | unsigned int last_cp_used; /* Index of last mailbox used */ | |||
511 | unsigned int iocount; /* Total i/o done for this board */ | |||
512 | int board_number; /* Number of this board */ | |||
513 | char board_name[16]; /* Name of this board */ | |||
514 | char board_id[256]; /* data from INQUIRY on this board */ | |||
515 | int in_reset; /* True if board is doing a reset */ | |||
516 | int target_to[MAX_TARGET8][MAX_CHANNEL1]; /* N. of timeout errors on target */ | |||
517 | int target_redo[MAX_TARGET8][MAX_CHANNEL1]; /* If TRUE redo i/o on target */ | |||
518 | unsigned int retries; /* Number of internal retries */ | |||
519 | unsigned long last_retried_pid; /* Pid of last retried command */ | |||
520 | unsigned char subversion; /* Bus type, either ISA or ESA */ | |||
521 | unsigned char heads; | |||
522 | unsigned char sectors; | |||
523 | ||||
524 | /* slot != 0 for the U24F, slot == 0 for both the U14F and U34F */ | |||
525 | unsigned char slot; | |||
526 | }; | |||
527 | ||||
528 | static struct Scsi_Host *sh[MAX_BOARDS(3 + 1 + 0 + 0) + 1]; | |||
529 | static const char *driver_name = "Ux4F"; | |||
530 | static char sha[MAX_BOARDS(3 + 1 + 0 + 0)]; | |||
531 | ||||
532 | /* Initialize num_boards so that ihdlr can work while detect is in progress */ | |||
533 | static unsigned int num_boards = MAX_BOARDS(3 + 1 + 0 + 0); | |||
534 | ||||
535 | static unsigned long io_port[] __initdata = { | |||
536 | ||||
537 | /* Space for MAX_INT_PARAM ports usable while loading as a module */ | |||
538 | SKIP(~0UL), SKIP(~0UL), SKIP(~0UL), SKIP(~0UL), SKIP(~0UL), SKIP(~0UL), SKIP(~0UL), SKIP(~0UL), | |||
539 | SKIP(~0UL), SKIP(~0UL), | |||
540 | ||||
541 | /* Possible ISA/VESA ports */ | |||
542 | 0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140, | |||
543 | ||||
544 | /* End of list */ | |||
545 | 0x0 | |||
546 | }; | |||
547 | ||||
548 | #define HD(board)((struct hostdata *) &sh[board]->hostdata) ((struct hostdata *) &sh[board]->hostdata) | |||
549 | #define BN(board)(((struct hostdata *) &sh[board]->hostdata)->board_name ) (HD(board)((struct hostdata *) &sh[board]->hostdata)->board_name) | |||
550 | ||||
551 | #define SWAP_BYTE(x)((unsigned long)( (((unsigned long)(x) & 0x000000ffU) << 24) | (((unsigned long)(x) & 0x0000ff00U) << 8) | ( ((unsigned long)(x) & 0x00ff0000U) >> 8) | (((unsigned long)(x) & 0xff000000U) >> 24))) ((unsigned long)( \ | |||
552 | (((unsigned long)(x) & 0x000000ffU) << 24) | \ | |||
553 | (((unsigned long)(x) & 0x0000ff00U) << 8) | \ | |||
554 | (((unsigned long)(x) & 0x00ff0000U) >> 8) | \ | |||
555 | (((unsigned long)(x) & 0xff000000U) >> 24))) | |||
556 | ||||
557 | #if defined(__BIG_ENDIAN) | |||
558 | #define H2DEV(x)(x) SWAP_BYTE(x)((unsigned long)( (((unsigned long)(x) & 0x000000ffU) << 24) | (((unsigned long)(x) & 0x0000ff00U) << 8) | ( ((unsigned long)(x) & 0x00ff0000U) >> 8) | (((unsigned long)(x) & 0xff000000U) >> 24))) | |||
559 | #else | |||
560 | #define H2DEV(x)(x) (x) | |||
561 | #endif | |||
562 | ||||
563 | #define DEV2H(x)(x) H2DEV(x)(x) | |||
564 | #define V2DEV(addr)((addr) ? (virt_to_phys((void *)addr)) : 0) ((addr) ? H2DEV(virt_to_bus((void *)addr))(virt_to_phys((void *)addr)) : 0) | |||
565 | #define DEV2V(addr)((addr) ? (phys_to_virt((unsigned long)addr)) : 0) ((addr) ? DEV2H(bus_to_virt((unsigned long)addr))(phys_to_virt((unsigned long)addr)) : 0) | |||
566 | ||||
567 | static void do_interrupt_handler(int, void *, struct pt_regs *); | |||
568 | static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); | |||
569 | static int do_trace = FALSE0; | |||
570 | static int setup_done = FALSE0; | |||
571 | static int link_statistics = 0; | |||
572 | static int ext_tran = FALSE0; | |||
573 | ||||
574 | #if defined(HAVE_OLD_UX4F_FIRMWARE) | |||
575 | static int have_old_firmware = TRUE1; | |||
576 | #else | |||
577 | static int have_old_firmware = FALSE0; | |||
578 | #endif | |||
579 | ||||
580 | #if defined(CONFIG_SCSI_U14_34F_LINKED_COMMANDS) | |||
581 | static int linked_comm = TRUE1; | |||
582 | #else | |||
583 | static int linked_comm = FALSE0; | |||
584 | #endif | |||
585 | ||||
586 | #if defined(CONFIG_SCSI_U14_34F_MAX_TAGS) | |||
587 | static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS; | |||
588 | #else | |||
589 | static int max_queue_depth = MAX_CMD_PER_LUN2; | |||
590 | #endif | |||
591 | ||||
592 | static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) { | |||
593 | Scsi_Device *dev; | |||
594 | int j, ntag = 0, nuntag = 0, tqd, utqd; | |||
595 | IRQ_FLAGSunsigned long irq_flags; | |||
596 | ||||
597 | IRQ_LOCK_SAVEdo {__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory"); __asm__ __volatile__ ("cli": : :"memory");} while (0); | |||
598 | j = ((struct hostdata *) host->hostdata)->board_number; | |||
599 | ||||
600 | for(dev = devlist; dev; dev = dev->next) { | |||
601 | ||||
602 | if (dev->host != host) continue; | |||
603 | ||||
604 | if (TLDEV(dev->type)((dev->type) == 0x00 || (dev->type) == 0x05) && (dev->tagged_supported || linked_comm)) | |||
605 | ntag++; | |||
606 | else | |||
607 | nuntag++; | |||
608 | } | |||
609 | ||||
610 | utqd = MAX_CMD_PER_LUN2; | |||
611 | ||||
612 | tqd = (host->can_queue - utqd * nuntag) / (ntag ? ntag : 1); | |||
613 | ||||
614 | if (tqd > max_queue_depth) tqd = max_queue_depth; | |||
615 | ||||
616 | if (tqd < MAX_CMD_PER_LUN2) tqd = MAX_CMD_PER_LUN2; | |||
617 | ||||
618 | for(dev = devlist; dev; dev = dev->next) { | |||
619 | char *tag_suffix = "", *link_suffix = ""; | |||
620 | ||||
621 | if (dev->host != host) continue; | |||
622 | ||||
623 | if (TLDEV(dev->type)((dev->type) == 0x00 || (dev->type) == 0x05) && (dev->tagged_supported || linked_comm)) | |||
624 | dev->queue_depth = tqd; | |||
625 | else | |||
626 | dev->queue_depth = utqd; | |||
627 | ||||
628 | if (TLDEV(dev->type)((dev->type) == 0x00 || (dev->type) == 0x05)) { | |||
629 | if (linked_comm && dev->queue_depth > 2) | |||
630 | link_suffix = ", sorted"; | |||
631 | else | |||
632 | link_suffix = ", unsorted"; | |||
633 | } | |||
634 | ||||
635 | if (dev->tagged_supported && TLDEV(dev->type)((dev->type) == 0x00 || (dev->type) == 0x05) && dev->tagged_queue) | |||
636 | tag_suffix = ", tagged"; | |||
637 | else if (dev->tagged_supported && TLDEV(dev->type)((dev->type) == 0x00 || (dev->type) == 0x05)) | |||
638 | tag_suffix = ", untagged"; | |||
639 | ||||
640 | printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", | |||
641 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), host->host_no, dev->channel, dev->id, dev->lun, | |||
642 | dev->queue_depth, link_suffix, tag_suffix); | |||
643 | } | |||
644 | ||||
645 | IRQ_UNLOCK_RESTOREdo {__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); | |||
646 | return; | |||
647 | } | |||
648 | ||||
649 | static inlineinline __attribute__((always_inline)) int wait_on_busy(unsigned long iobase, unsigned int loop) { | |||
650 | ||||
651 | while (inb(iobase + REG_LCL_INTR)((__builtin_constant_p((iobase + 1)) && (iobase + 1) < 256) ? __inbc(iobase + 1) : __inb(iobase + 1)) & BSY_ASSERTED0x01) { | |||
652 | udelay(1L)(__builtin_constant_p(1L) ? __const_udelay((1L) * 0x10c6ul) : __udelay(1L)); | |||
653 | if (--loop == 0) return TRUE1; | |||
654 | } | |||
655 | ||||
656 | return FALSE0; | |||
657 | } | |||
658 | ||||
659 | static int board_inquiry(unsigned int j) { | |||
660 | struct mscp *cpp; | |||
661 | unsigned int time, limit = 0; | |||
662 | ||||
663 | cpp = &HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[0]; | |||
664 | memset(cpp, 0, sizeof(struct mscp))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof(struct mscp))) ? __constant_c_and_count_memset(((cpp)),((0x01010101UL *(unsigned char)(0))),((sizeof(struct mscp)))) : __constant_c_memset (((cpp)),((0x01010101UL*(unsigned char)(0))),((sizeof(struct mscp ))))) : (__builtin_constant_p((sizeof(struct mscp))) ? __memset_generic ((((cpp))),(((0))),(((sizeof(struct mscp))))) : __memset_generic (((cpp)),((0)),((sizeof(struct mscp)))))); | |||
665 | cpp->opcode = OP_HOST_ADAPTER0x1; | |||
666 | cpp->xdir = DTD_IN0x1; | |||
667 | cpp->data_address = V2DEV(HD(j)->board_id)((((struct hostdata *) &sh[j]->hostdata)->board_id) ? (virt_to_phys((void *)((struct hostdata *) &sh[j]-> hostdata)->board_id)) : 0); | |||
668 | cpp->data_len = H2DEV(sizeof(HD(j)->board_id))(sizeof(((struct hostdata *) &sh[j]->hostdata)->board_id )); | |||
669 | cpp->scsi_cdbs_len = 6; | |||
670 | cpp->scsi_cdbs[0] = HA_CMD_INQUIRY0x1; | |||
671 | ||||
672 | if (wait_on_busy(sh[j]->io_port, MAXLOOP10000)) { | |||
673 | printk("%s: board_inquiry, adapter busy.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
674 | return TRUE1; | |||
675 | } | |||
676 | ||||
677 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[0] = IGNORE4; | |||
678 | ||||
679 | /* Clear the interrupt indication */ | |||
680 | outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR)((__builtin_constant_p((sh[j]->io_port + 3)) && (sh [j]->io_port + 3) < 256) ? __outbc((0x01),(sh[j]->io_port + 3)) : __outb((0x01),(sh[j]->io_port + 3))); | |||
681 | ||||
682 | /* Store pointer in OGM address bytes */ | |||
683 | outl(V2DEV(cpp), sh[j]->io_port + REG_OGM)((__builtin_constant_p((sh[j]->io_port + 8)) && (sh [j]->io_port + 8) < 256) ? __outlc((((cpp) ? (virt_to_phys ((void *)cpp)) : 0)),(sh[j]->io_port + 8)) : __outl((((cpp ) ? (virt_to_phys((void *)cpp)) : 0)),(sh[j]->io_port + 8) )); | |||
684 | ||||
685 | /* Issue OGM interrupt */ | |||
686 | outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR)((__builtin_constant_p((sh[j]->io_port + 1)) && (sh [j]->io_port + 1) < 256) ? __outbc((0x01),(sh[j]->io_port + 1)) : __outb((0x01),(sh[j]->io_port + 1))); | |||
687 | ||||
688 | SPIN_UNLOCK | |||
689 | IRQ_UNLOCK__asm__ __volatile__ ("sti": : :"memory"); | |||
690 | time = jiffies; | |||
691 | while ((jiffies - time) < HZ100 && limit++ < 20000) udelay(100L)(__builtin_constant_p(100L) ? __const_udelay((100L) * 0x10c6ul ) : __udelay(100L)); | |||
692 | IRQ_LOCK__asm__ __volatile__ ("cli": : :"memory"); | |||
693 | SPIN_LOCK | |||
694 | ||||
695 | if (cpp->adapter_status || HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[0] != FREE0) { | |||
696 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[0] = FREE0; | |||
697 | printk("%s: board_inquiry, err 0x%x.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), cpp->adapter_status); | |||
698 | return TRUE1; | |||
699 | } | |||
700 | ||||
701 | return FALSE0; | |||
702 | } | |||
703 | ||||
704 | __initfunc (static inline int port_detect \static inline __attribute__((always_inline)) int port_detect ( unsigned long port_base, unsigned int j, Scsi_Host_Template * tpnt) | |||
705 | (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt))static inline __attribute__((always_inline)) int port_detect ( unsigned long port_base, unsigned int j, Scsi_Host_Template * tpnt) { | |||
706 | unsigned char irq, dma_channel, subversion, i; | |||
707 | unsigned char in_byte; | |||
708 | char *bus_type, dma_name[16]; | |||
709 | ||||
710 | /* Allowed BIOS base addresses (NULL indicates reserved) */ | |||
711 | void *bios_segment_table[8] = { | |||
712 | NULL((void *) 0), | |||
713 | (void *) 0xc4000, (void *) 0xc8000, (void *) 0xcc000, (void *) 0xd0000, | |||
714 | (void *) 0xd4000, (void *) 0xd8000, (void *) 0xdc000 | |||
715 | }; | |||
716 | ||||
717 | /* Allowed IRQs */ | |||
718 | unsigned char interrupt_table[4] = { 15, 14, 11, 10 }; | |||
719 | ||||
720 | /* Allowed DMA channels for ISA (0 indicates reserved) */ | |||
721 | unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; | |||
722 | ||||
723 | /* Head/sector mappings */ | |||
724 | struct { | |||
725 | unsigned char heads; | |||
726 | unsigned char sectors; | |||
727 | } mapping_table[4] = { | |||
728 | { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 } | |||
729 | }; | |||
730 | ||||
731 | struct config_1 { | |||
732 | unsigned char bios_segment: 3; | |||
733 | unsigned char removable_disks_as_fixed: 1; | |||
734 | unsigned char interrupt: 2; | |||
735 | unsigned char dma_channel: 2; | |||
736 | } config_1; | |||
737 | ||||
738 | struct config_2 { | |||
739 | unsigned char ha_scsi_id: 3; | |||
740 | unsigned char mapping_mode: 2; | |||
741 | unsigned char bios_drive_number: 1; | |||
742 | unsigned char tfr_port: 2; | |||
743 | } config_2; | |||
744 | ||||
745 | char name[16]; | |||
746 | ||||
747 | sprintflinux_sprintf(name, "%s%d", driver_name, j); | |||
748 | ||||
749 | if(check_region(port_base, REGION_SIZE13)) { | |||
| ||||
750 | printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base); | |||
751 | return FALSE0; | |||
752 | } | |||
753 | ||||
754 | if (inb(port_base + REG_PRODUCT_ID1)((__builtin_constant_p((port_base + 4)) && (port_base + 4) < 256) ? __inbc(port_base + 4) : __inb(port_base + 4 )) != PRODUCT_ID10x56) return FALSE0; | |||
755 | ||||
756 | in_byte = inb(port_base + REG_PRODUCT_ID2)((__builtin_constant_p((port_base + 5)) && (port_base + 5) < 256) ? __inbc(port_base + 5) : __inb(port_base + 5 )); | |||
757 | ||||
758 | if ((in_byte & 0xf0) != PRODUCT_ID20x40) return FALSE0; | |||
759 | ||||
760 | *(char *)&config_1 = inb(port_base + REG_CONFIG1)((__builtin_constant_p((port_base + 6)) && (port_base + 6) < 256) ? __inbc(port_base + 6) : __inb(port_base + 6 )); | |||
761 | *(char *)&config_2 = inb(port_base + REG_CONFIG2)((__builtin_constant_p((port_base + 7)) && (port_base + 7) < 256) ? __inbc(port_base + 7) : __inb(port_base + 7 )); | |||
762 | ||||
763 | irq = interrupt_table[config_1.interrupt]; | |||
| ||||
764 | dma_channel = dma_channel_table[config_1.dma_channel]; | |||
765 | subversion = (in_byte & 0x0f); | |||
766 | ||||
767 | /* Board detected, allocate its IRQ */ | |||
768 | if (request_irq(irq, do_interrupt_handler, | |||
769 | SA_INTERRUPT0x20000000 | ((subversion == ESA1) ? SA_SHIRQ0x04000000 : 0), | |||
770 | driver_name, (void *) &sha[j])) { | |||
771 | printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq); | |||
772 | return FALSE0; | |||
773 | } | |||
774 | ||||
775 | if (subversion == ISA0 && request_dma(dma_channel, driver_name)) { | |||
776 | printk("%s: unable to allocate DMA channel %u, detaching.\n", | |||
777 | name, dma_channel); | |||
778 | free_irq(irq, &sha[j]); | |||
779 | return FALSE0; | |||
780 | } | |||
781 | ||||
782 | if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING0; | |||
783 | ||||
784 | #if LINUX_VERSION_CODE131108 >= LinuxVersionCode(2,1,101)(((2)<<16)+((1)<<8)+(101)) | |||
785 | tpnt->use_new_eh_code = use_new_eh_code; | |||
786 | #else | |||
787 | use_new_eh_code = FALSE0; | |||
788 | #endif | |||
789 | ||||
790 | sh[j] = scsi_register(tpnt, sizeof(struct hostdata)); | |||
791 | ||||
792 | if (sh[j] == NULL((void *) 0)) { | |||
793 | printk("%s: unable to register host, detaching.\n", name); | |||
794 | ||||
795 | free_irq(irq, &sha[j]); | |||
796 | ||||
797 | if (subversion == ISA0) free_dma(dma_channel); | |||
798 | ||||
799 | return FALSE0; | |||
800 | } | |||
801 | ||||
802 | sh[j]->io_port = port_base; | |||
803 | sh[j]->unique_id = port_base; | |||
804 | sh[j]->n_io_port = REGION_SIZE13; | |||
805 | sh[j]->base = bios_segment_table[config_1.bios_segment]; | |||
806 | sh[j]->irq = irq; | |||
807 | sh[j]->sg_tablesize = MAX_SGLIST32; | |||
808 | sh[j]->this_id = config_2.ha_scsi_id; | |||
809 | sh[j]->can_queue = MAX_MAILBOXES16; | |||
810 | sh[j]->cmd_per_lun = MAX_CMD_PER_LUN2; | |||
811 | sh[j]->select_queue_depths = select_queue_depths; | |||
812 | ||||
813 | #if defined(DEBUG_DETECT) | |||
814 | { | |||
815 | unsigned char sys_mask, lcl_mask; | |||
816 | ||||
817 | sys_mask = inb(sh[j]->io_port + REG_SYS_MASK)((__builtin_constant_p((sh[j]->io_port + 2)) && (sh [j]->io_port + 2) < 256) ? __inbc(sh[j]->io_port + 2 ) : __inb(sh[j]->io_port + 2)); | |||
818 | lcl_mask = inb(sh[j]->io_port + REG_LCL_MASK)((__builtin_constant_p((sh[j]->io_port + 0)) && (sh [j]->io_port + 0) < 256) ? __inbc(sh[j]->io_port + 0 ) : __inb(sh[j]->io_port + 0)); | |||
819 | printk("SYS_MASK 0x%x, LCL_MASK 0x%x.\n", sys_mask, lcl_mask); | |||
820 | } | |||
821 | #endif | |||
822 | ||||
823 | /* Probably a bogus host scsi id, set it to the dummy value */ | |||
824 | if (sh[j]->this_id == 0) sh[j]->this_id = -1; | |||
825 | ||||
826 | /* If BIOS is disabled, force enable interrupts */ | |||
827 | if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK)((__builtin_constant_p((sh[j]->io_port + 2)) && (sh [j]->io_port + 2) < 256) ? __outbc((0x81),(sh[j]->io_port + 2)) : __outb((0x81),(sh[j]->io_port + 2))); | |||
828 | ||||
829 | /* Register the I/O space that we use */ | |||
830 | request_region(sh[j]->io_port, sh[j]->n_io_port, driver_name); | |||
831 | ||||
832 | memset(HD(j), 0, sizeof(struct hostdata))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof(struct hostdata))) ? __constant_c_and_count_memset(((((struct hostdata *) &sh[j]->hostdata))),((0x01010101UL*(unsigned char) (0))),((sizeof(struct hostdata)))) : __constant_c_memset((((( struct hostdata *) &sh[j]->hostdata))),((0x01010101UL* (unsigned char)(0))),((sizeof(struct hostdata))))) : (__builtin_constant_p ((sizeof(struct hostdata))) ? __memset_generic((((((struct hostdata *) &sh[j]->hostdata)))),(((0))),(((sizeof(struct hostdata ))))) : __memset_generic(((((struct hostdata *) &sh[j]-> hostdata))),((0)),((sizeof(struct hostdata)))))); | |||
833 | HD(j)((struct hostdata *) &sh[j]->hostdata)->heads = mapping_table[config_2.mapping_mode].heads; | |||
834 | HD(j)((struct hostdata *) &sh[j]->hostdata)->sectors = mapping_table[config_2.mapping_mode].sectors; | |||
835 | HD(j)((struct hostdata *) &sh[j]->hostdata)->subversion = subversion; | |||
836 | HD(j)((struct hostdata *) &sh[j]->hostdata)->board_number = j; | |||
837 | ||||
838 | if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST16; | |||
839 | ||||
840 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->subversion == ESA1) { | |||
841 | sh[j]->unchecked_isa_dma = FALSE0; | |||
842 | sh[j]->dma_channel = NO_DMA0xff; | |||
843 | sprintflinux_sprintf(BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), "U34F%d", j); | |||
844 | bus_type = "VESA"; | |||
845 | } | |||
846 | else { | |||
847 | sh[j]->wish_block = TRUE1; | |||
848 | sh[j]->unchecked_isa_dma = TRUE1; | |||
849 | disable_dma(dma_channel); | |||
850 | clear_dma_ff(dma_channel); | |||
851 | set_dma_mode(dma_channel, DMA_MODE_CASCADE0xC0); | |||
852 | enable_dma(dma_channel); | |||
853 | sh[j]->dma_channel = dma_channel; | |||
854 | sprintflinux_sprintf(BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), "U14F%d", j); | |||
855 | bus_type = "ISA"; | |||
856 | } | |||
857 | ||||
858 | sh[j]->max_channel = MAX_CHANNEL1 - 1; | |||
859 | sh[j]->max_id = MAX_TARGET8; | |||
860 | sh[j]->max_lun = MAX_LUN8; | |||
861 | ||||
862 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->subversion == ISA0 && !board_inquiry(j)) { | |||
863 | HD(j)((struct hostdata *) &sh[j]->hostdata)->board_id[40] = 0; | |||
864 | ||||
865 | if (strcmp(&HD(j)((struct hostdata *) &sh[j]->hostdata)->board_id[32], "06000600")) { | |||
866 | printk("%s: %s.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), &HD(j)((struct hostdata *) &sh[j]->hostdata)->board_id[8]); | |||
867 | printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n", | |||
868 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), &HD(j)((struct hostdata *) &sh[j]->hostdata)->board_id[32]); | |||
869 | sh[j]->hostt->use_clustering = DISABLE_CLUSTERING0; | |||
870 | sh[j]->sg_tablesize = MAX_SAFE_SGLIST16; | |||
871 | } | |||
872 | } | |||
873 | ||||
874 | if (dma_channel == NO_DMA0xff) sprintflinux_sprintf(dma_name, "%s", "BMST"); | |||
875 | else sprintflinux_sprintf(dma_name, "DMA %u", dma_channel); | |||
876 | ||||
877 | for (i = 0; i < sh[j]->can_queue; i++) | |||
878 | if (! ((&HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i])->sglist = kmalloclinux_kmalloc( | |||
879 | sh[j]->sg_tablesize * sizeof(struct sg_list), | |||
880 | (sh[j]->unchecked_isa_dma ? GFP_DMA0x80 : 0) | GFP_ATOMIC0x01))) { | |||
881 | printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
882 | u14_34f_release(sh[j]); | |||
883 | return FALSE0; | |||
884 | } | |||
885 | ||||
886 | if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN(16 - 2)) | |||
887 | max_queue_depth = MAX_TAGGED_CMD_PER_LUN(16 - 2); | |||
888 | ||||
889 | if (max_queue_depth < MAX_CMD_PER_LUN2) max_queue_depth = MAX_CMD_PER_LUN2; | |||
890 | ||||
891 | if (j == 0) { | |||
892 | printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n"); | |||
893 | printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c, et:%c.\n", | |||
894 | driver_name, YESNO(have_old_firmware)((have_old_firmware) ? 'y' : 'n'), YESNO(linked_comm)((linked_comm) ? 'y' : 'n'), | |||
895 | max_queue_depth, YESNO(use_new_eh_code)((use_new_eh_code) ? 'y' : 'n'), YESNO(ext_tran)((ext_tran) ? 'y' : 'n')); | |||
896 | } | |||
897 | ||||
898 | printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n", | |||
899 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), bus_type, (unsigned long)sh[j]->io_port, (int)sh[j]->base, | |||
900 | sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue); | |||
901 | ||||
902 | if (sh[j]->max_id > 8 || sh[j]->max_lun > 8) | |||
903 | printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n", | |||
904 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), sh[j]->max_id, sh[j]->max_lun); | |||
905 | ||||
906 | for (i = 0; i <= sh[j]->max_channel; i++) | |||
907 | printk("%s: SCSI channel %u enabled, host target ID %d.\n", | |||
908 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, sh[j]->this_id); | |||
909 | ||||
910 | return TRUE1; | |||
911 | } | |||
912 | ||||
913 | __initfunc (void u14_34f_setup(char *str, int *ints))void u14_34f_setup(char *str, int *ints) { | |||
914 | int i, argc = ints[0]; | |||
915 | char *cur = str, *pc; | |||
916 | ||||
917 | if (argc > 0) { | |||
918 | ||||
919 | if (argc > MAX_INT_PARAM10) argc = MAX_INT_PARAM10; | |||
920 | ||||
921 | for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; | |||
922 | ||||
923 | io_port[i] = 0; | |||
924 | setup_done = TRUE1; | |||
925 | } | |||
926 | ||||
927 | while (cur && (pc = strchr(cur, ':'))) { | |||
928 | int val = 0, c = *++pc; | |||
929 | ||||
930 | if (c == 'n' || c == 'N') val = FALSE0; | |||
931 | else if (c == 'y' || c == 'Y') val = TRUE1; | |||
932 | else val = (int) simple_strtoul(pc, NULL((void *) 0), 0); | |||
933 | ||||
934 | if (!strncmp(cur, "lc:", 3)) linked_comm = val; | |||
935 | else if (!strncmp(cur, "of:", 3)) have_old_firmware = val; | |||
936 | else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val; | |||
937 | else if (!strncmp(cur, "ls:", 3)) link_statistics = val; | |||
938 | else if (!strncmp(cur, "eh:", 3)) use_new_eh_code = val; | |||
939 | else if (!strncmp(cur, "et:", 3)) ext_tran = val; | |||
940 | ||||
941 | if ((cur = strchr(cur, ','))) ++cur; | |||
942 | } | |||
943 | ||||
944 | return; | |||
945 | } | |||
946 | ||||
947 | __initfunc (int u14_34f_detect(Scsi_Host_Template *tpnt))int u14_34f_detect(Scsi_Host_Template *tpnt) { | |||
948 | unsigned int j = 0, k; | |||
949 | IRQ_FLAGSunsigned long irq_flags; | |||
950 | ||||
951 | IRQ_LOCK_SAVEdo {__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory"); __asm__ __volatile__ ("cli": : :"memory");} while (0); | |||
952 | tpnt->proc_dir = &proc_scsi_u14_34f; | |||
953 | ||||
954 | #if defined(MODULE) | |||
955 | /* io_port could have been modified when loading as a module */ | |||
956 | if(io_port[0] != SKIP(~0UL)) { | |||
957 | setup_done = TRUE1; | |||
958 | io_port[MAX_INT_PARAM10] = 0; | |||
959 | } | |||
960 | #endif | |||
961 | ||||
962 | for (k = 0; k < MAX_BOARDS(3 + 1 + 0 + 0) + 1; k++) sh[k] = NULL((void *) 0); | |||
963 | ||||
964 | for (k = 0; io_port[k]; k++) { | |||
965 | ||||
966 | if (io_port[k] == SKIP(~0UL)) continue; | |||
967 | ||||
968 | if (j < MAX_BOARDS(3 + 1 + 0 + 0) && port_detect(io_port[k], j, tpnt)) j++; | |||
969 | } | |||
970 | ||||
971 | num_boards = j; | |||
972 | IRQ_UNLOCK_RESTOREdo {__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); | |||
973 | return j; | |||
974 | } | |||
975 | ||||
976 | static inlineinline __attribute__((always_inline)) void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) { | |||
977 | unsigned int k, data_len = 0; | |||
978 | struct scatterlist *sgpnt; | |||
979 | ||||
980 | sgpnt = (struct scatterlist *) SCpnt->request_buffer; | |||
981 | ||||
982 | for (k = 0; k < SCpnt->use_sg; k++) { | |||
983 | cpp->sglist[k].address = V2DEV(sgpnt[k].address)((sgpnt[k].address) ? (virt_to_phys((void *)sgpnt[k].address) ) : 0); | |||
984 | cpp->sglist[k].num_bytes = H2DEV(sgpnt[k].length)(sgpnt[k].length); | |||
985 | data_len += sgpnt[k].length; | |||
986 | } | |||
987 | ||||
988 | cpp->use_sg = SCpnt->use_sg; | |||
989 | cpp->data_address = V2DEV(cpp->sglist)((cpp->sglist) ? (virt_to_phys((void *)cpp->sglist)) : 0 ); | |||
990 | cpp->data_len = H2DEV(data_len)(data_len); | |||
991 | } | |||
992 | ||||
993 | static inlineinline __attribute__((always_inline)) int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { | |||
994 | unsigned int i, j, k; | |||
995 | struct mscp *cpp; | |||
996 | ||||
997 | static const unsigned char data_out_cmds[] = { | |||
998 | 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, | |||
999 | 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, | |||
1000 | 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b | |||
1001 | }; | |||
1002 | ||||
1003 | static const unsigned char data_none_cmds[] = { | |||
1004 | 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, | |||
1005 | 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, | |||
1006 | 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5 | |||
1007 | }; | |||
1008 | ||||
1009 | /* j is the board number */ | |||
1010 | j = ((struct hostdata *) SCpnt->host->hostdata)->board_number; | |||
1011 | ||||
1012 | if (SCpnt->host_scribble) | |||
1013 | panic("%s: qcomm, pid %ld, SCpnt %p already active.\n", | |||
1014 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCpnt->pid, SCpnt); | |||
1015 | ||||
1016 | /* i is the mailbox number, look for the first free mailbox | |||
1017 | starting from last_cp_used */ | |||
1018 | i = HD(j)((struct hostdata *) &sh[j]->hostdata)->last_cp_used + 1; | |||
1019 | ||||
1020 | for (k = 0; k < sh[j]->can_queue; k++, i++) { | |||
1021 | ||||
1022 | if (i >= sh[j]->can_queue) i = 0; | |||
1023 | ||||
1024 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == FREE0) { | |||
1025 | HD(j)((struct hostdata *) &sh[j]->hostdata)->last_cp_used = i; | |||
1026 | break; | |||
1027 | } | |||
1028 | } | |||
1029 | ||||
1030 | if (k == sh[j]->can_queue) { | |||
1031 | printk("%s: qcomm, no free mailbox.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1032 | return 1; | |||
1033 | } | |||
1034 | ||||
1035 | /* Set pointer to control packet structure */ | |||
1036 | cpp = &HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i]; | |||
1037 | ||||
1038 | memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof(struct mscp) - sizeof(struct sg_list *))) ? __constant_c_and_count_memset (((cpp)),((0x01010101UL*(unsigned char)(0))),((sizeof(struct mscp ) - sizeof(struct sg_list *)))) : __constant_c_memset(((cpp)) ,((0x01010101UL*(unsigned char)(0))),((sizeof(struct mscp) - sizeof (struct sg_list *))))) : (__builtin_constant_p((sizeof(struct mscp) - sizeof(struct sg_list *))) ? __memset_generic((((cpp ))),(((0))),(((sizeof(struct mscp) - sizeof(struct sg_list *) )))) : __memset_generic(((cpp)),((0)),((sizeof(struct mscp) - sizeof(struct sg_list *)))))); | |||
1039 | SCpnt->scsi_done = done; | |||
1040 | cpp->index = i; | |||
1041 | SCpnt->host_scribble = (unsigned char *) &cpp->index; | |||
1042 | ||||
1043 | if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n", | |||
1044 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->channel, SCpnt->target, | |||
1045 | SCpnt->lun, SCpnt->pid); | |||
1046 | ||||
1047 | cpp->xdir = DTD_IN0x1; | |||
1048 | ||||
1049 | for (k = 0; k < ARRAY_SIZE(data_out_cmds)(sizeof (data_out_cmds) / sizeof (data_out_cmds)[0]); k++) | |||
1050 | if (SCpnt->cmnd[0] == data_out_cmds[k]) { | |||
1051 | cpp->xdir = DTD_OUT0x2; | |||
1052 | break; | |||
1053 | } | |||
1054 | ||||
1055 | if (cpp->xdir == DTD_IN0x1) | |||
1056 | for (k = 0; k < ARRAY_SIZE(data_none_cmds)(sizeof (data_none_cmds) / sizeof (data_none_cmds)[0]); k++) | |||
1057 | if (SCpnt->cmnd[0] == data_none_cmds[k]) { | |||
1058 | cpp->xdir = DTD_NONE0x3; | |||
1059 | break; | |||
1060 | } | |||
1061 | ||||
1062 | cpp->opcode = OP_SCSI0x2; | |||
1063 | cpp->channel = SCpnt->channel; | |||
1064 | cpp->target = SCpnt->target; | |||
1065 | cpp->lun = SCpnt->lun; | |||
1066 | cpp->SCpnt = SCpnt; | |||
1067 | cpp->sense_addr = V2DEV(SCpnt->sense_buffer)((SCpnt->sense_buffer) ? (virt_to_phys((void *)SCpnt->sense_buffer )) : 0); | |||
1068 | cpp->sense_len = sizeof SCpnt->sense_buffer; | |||
1069 | ||||
1070 | if (SCpnt->use_sg) { | |||
1071 | cpp->sg = TRUE1; | |||
1072 | build_sg_list(cpp, SCpnt); | |||
1073 | } | |||
1074 | else { | |||
1075 | cpp->data_address = V2DEV(SCpnt->request_buffer)((SCpnt->request_buffer) ? (virt_to_phys((void *)SCpnt-> request_buffer)) : 0); | |||
1076 | cpp->data_len = H2DEV(SCpnt->request_bufflen)(SCpnt->request_bufflen); | |||
1077 | } | |||
1078 | ||||
1079 | cpp->scsi_cdbs_len = SCpnt->cmd_len; | |||
1080 | memcpy(cpp->scsi_cdbs, SCpnt->cmnd, cpp->scsi_cdbs_len)(__builtin_constant_p(cpp->scsi_cdbs_len) ? __constant_memcpy ((cpp->scsi_cdbs),(SCpnt->cmnd),(cpp->scsi_cdbs_len) ) : __memcpy((cpp->scsi_cdbs),(SCpnt->cmnd),(cpp->scsi_cdbs_len ))); | |||
1081 | ||||
1082 | if (linked_comm && SCpnt->device->queue_depth > 2 | |||
1083 | && TLDEV(SCpnt->device->type)((SCpnt->device->type) == 0x00 || (SCpnt->device-> type) == 0x05)) { | |||
1084 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = READY5; | |||
1085 | flush_dev(SCpnt->device, SCpnt->request.sector, j, FALSE0); | |||
1086 | return 0; | |||
1087 | } | |||
1088 | ||||
1089 | if (wait_on_busy(sh[j]->io_port, MAXLOOP10000)) { | |||
1090 | SCpnt->host_scribble = NULL((void *) 0); | |||
1091 | printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n", | |||
1092 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid); | |||
1093 | return 1; | |||
1094 | } | |||
1095 | ||||
1096 | /* Store pointer in OGM address bytes */ | |||
1097 | outl(V2DEV(cpp), sh[j]->io_port + REG_OGM)((__builtin_constant_p((sh[j]->io_port + 8)) && (sh [j]->io_port + 8) < 256) ? __outlc((((cpp) ? (virt_to_phys ((void *)cpp)) : 0)),(sh[j]->io_port + 8)) : __outl((((cpp ) ? (virt_to_phys((void *)cpp)) : 0)),(sh[j]->io_port + 8) )); | |||
1098 | ||||
1099 | /* Issue OGM interrupt */ | |||
1100 | outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR)((__builtin_constant_p((sh[j]->io_port + 1)) && (sh [j]->io_port + 1) < 256) ? __outbc((0x01),(sh[j]->io_port + 1)) : __outb((0x01),(sh[j]->io_port + 1))); | |||
1101 | ||||
1102 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = IN_USE1; | |||
1103 | return 0; | |||
1104 | } | |||
1105 | ||||
1106 | int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { | |||
1107 | int rtn; | |||
1108 | IRQ_FLAGSunsigned long irq_flags; | |||
1109 | ||||
1110 | IRQ_LOCK_SAVEdo {__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory"); __asm__ __volatile__ ("cli": : :"memory");} while (0); | |||
1111 | rtn = do_qcomm(SCpnt, done); | |||
1112 | IRQ_UNLOCK_RESTOREdo {__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); | |||
1113 | return rtn; | |||
1114 | } | |||
1115 | ||||
1116 | static inlineinline __attribute__((always_inline)) int do_old_abort(Scsi_Cmnd *SCarg) { | |||
1117 | unsigned int i, j; | |||
1118 | ||||
1119 | j = ((struct hostdata *) SCarg->host->hostdata)->board_number; | |||
1120 | ||||
1121 | if (SCarg->host_scribble == NULL((void *) 0) || | |||
1122 | (SCarg->serial_number_at_timeout && | |||
1123 | (SCarg->serial_number != SCarg->serial_number_at_timeout))) { | |||
1124 | printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n", | |||
1125 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid); | |||
1126 | return SCSI_ABORT_NOT_RUNNING4; | |||
1127 | } | |||
1128 | ||||
1129 | i = *(unsigned int *)SCarg->host_scribble; | |||
1130 | printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n", | |||
1131 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid); | |||
1132 | ||||
1133 | if (i >= sh[j]->can_queue) | |||
1134 | panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1135 | ||||
1136 | if (wait_on_busy(sh[j]->io_port, MAXLOOP10000)) { | |||
1137 | printk("%s: abort, timeout error.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1138 | return SCSI_ABORT_ERROR5; | |||
1139 | } | |||
1140 | ||||
1141 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == FREE0) { | |||
1142 | printk("%s: abort, mbox %d is free.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1143 | return SCSI_ABORT_NOT_RUNNING4; | |||
1144 | } | |||
1145 | ||||
1146 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == IN_USE1) { | |||
1147 | printk("%s: abort, mbox %d is in use.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1148 | ||||
1149 | if (SCarg != HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt) | |||
1150 | panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n", | |||
1151 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCarg, HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt); | |||
1152 | ||||
1153 | if (inb(sh[j]->io_port + REG_SYS_INTR)((__builtin_constant_p((sh[j]->io_port + 3)) && (sh [j]->io_port + 3) < 256) ? __inbc(sh[j]->io_port + 3 ) : __inb(sh[j]->io_port + 3)) & IRQ_ASSERTED0x01) | |||
1154 | printk("%s: abort, mbox %d, interrupt pending.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1155 | ||||
1156 | return SCSI_ABORT_SNOOZE0; | |||
1157 | } | |||
1158 | ||||
1159 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == IN_RESET3) { | |||
1160 | printk("%s: abort, mbox %d is in reset.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1161 | return SCSI_ABORT_ERROR5; | |||
1162 | } | |||
1163 | ||||
1164 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == LOCKED2) { | |||
1165 | printk("%s: abort, mbox %d is locked.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1166 | return SCSI_ABORT_NOT_RUNNING4; | |||
1167 | } | |||
1168 | ||||
1169 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == READY5 || HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == ABORTING6) { | |||
1170 | SCarg->result = DID_ABORT0x05 << 16; | |||
1171 | SCarg->host_scribble = NULL((void *) 0); | |||
1172 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1173 | printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", | |||
1174 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCarg->pid); | |||
1175 | SCarg->scsi_done(SCarg); | |||
1176 | return SCSI_ABORT_SUCCESS1; | |||
1177 | } | |||
1178 | ||||
1179 | panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1180 | } | |||
1181 | ||||
1182 | int u14_34f_old_abort(Scsi_Cmnd *SCarg) { | |||
1183 | int rtn; | |||
1184 | IRQ_FLAGSunsigned long irq_flags; | |||
1185 | ||||
1186 | IRQ_LOCK_SAVEdo {__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory"); __asm__ __volatile__ ("cli": : :"memory");} while (0); | |||
1187 | rtn = do_old_abort(SCarg); | |||
1188 | IRQ_UNLOCK_RESTOREdo {__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); | |||
1189 | return rtn; | |||
1190 | } | |||
1191 | ||||
1192 | #if LINUX_VERSION_CODE131108 >= LinuxVersionCode(2,1,101)(((2)<<16)+((1)<<8)+(101)) | |||
1193 | ||||
1194 | static inlineinline __attribute__((always_inline)) int do_abort(Scsi_Cmnd *SCarg) { | |||
1195 | unsigned int i, j; | |||
1196 | ||||
1197 | j = ((struct hostdata *) SCarg->host->hostdata)->board_number; | |||
1198 | ||||
1199 | if (SCarg->host_scribble == NULL((void *) 0)) { | |||
1200 | printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n", | |||
1201 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid); | |||
1202 | return SUCCESS; | |||
1203 | } | |||
1204 | ||||
1205 | i = *(unsigned int *)SCarg->host_scribble; | |||
1206 | printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n", | |||
1207 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid); | |||
1208 | ||||
1209 | if (i >= sh[j]->can_queue) | |||
1210 | panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1211 | ||||
1212 | if (wait_on_busy(sh[j]->io_port, MAXLOOP10000)) { | |||
1213 | printk("%s: abort, timeout error.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1214 | return FAILED; | |||
1215 | } | |||
1216 | ||||
1217 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == FREE0) { | |||
1218 | printk("%s: abort, mbox %d is free.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1219 | return SUCCESS; | |||
1220 | } | |||
1221 | ||||
1222 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == IN_USE1) { | |||
1223 | printk("%s: abort, mbox %d is in use.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1224 | ||||
1225 | if (SCarg != HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt) | |||
1226 | panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n", | |||
1227 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCarg, HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt); | |||
1228 | ||||
1229 | if (inb(sh[j]->io_port + REG_SYS_INTR)((__builtin_constant_p((sh[j]->io_port + 3)) && (sh [j]->io_port + 3) < 256) ? __inbc(sh[j]->io_port + 3 ) : __inb(sh[j]->io_port + 3)) & IRQ_ASSERTED0x01) | |||
1230 | printk("%s: abort, mbox %d, interrupt pending.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1231 | ||||
1232 | if (SCarg->eh_state == SCSI_STATE_TIMEOUT) { | |||
1233 | SCarg->host_scribble = NULL((void *) 0); | |||
1234 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1235 | printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n", | |||
1236 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCarg->pid); | |||
1237 | return SUCCESS; | |||
1238 | } | |||
1239 | ||||
1240 | return FAILED; | |||
1241 | } | |||
1242 | ||||
1243 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == IN_RESET3) { | |||
1244 | printk("%s: abort, mbox %d is in reset.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1245 | return FAILED; | |||
1246 | } | |||
1247 | ||||
1248 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == LOCKED2) { | |||
1249 | printk("%s: abort, mbox %d is locked.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1250 | return SUCCESS; | |||
1251 | } | |||
1252 | ||||
1253 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == READY5 || HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == ABORTING6) { | |||
1254 | SCarg->result = DID_ABORT0x05 << 16; | |||
1255 | SCarg->host_scribble = NULL((void *) 0); | |||
1256 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1257 | printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", | |||
1258 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCarg->pid); | |||
1259 | SCarg->scsi_done(SCarg); | |||
1260 | return SUCCESS; | |||
1261 | } | |||
1262 | ||||
1263 | panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1264 | } | |||
1265 | ||||
1266 | int u14_34f_abort(Scsi_Cmnd *SCarg) { | |||
1267 | ||||
1268 | return do_abort(SCarg); | |||
1269 | } | |||
1270 | ||||
1271 | #endif /* new_eh_code */ | |||
1272 | ||||
1273 | static inlineinline __attribute__((always_inline)) int do_old_reset(Scsi_Cmnd *SCarg) { | |||
1274 | unsigned int i, j, time, k, c, limit = 0; | |||
1275 | int arg_done = FALSE0; | |||
1276 | Scsi_Cmnd *SCpnt; | |||
1277 | ||||
1278 | j = ((struct hostdata *) SCarg->host->hostdata)->board_number; | |||
1279 | printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n", | |||
1280 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid); | |||
1281 | ||||
1282 | if (SCarg->host_scribble == NULL((void *) 0)) | |||
1283 | printk("%s: reset, pid %ld inactive.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCarg->pid); | |||
1284 | ||||
1285 | if (SCarg->serial_number_at_timeout && | |||
1286 | (SCarg->serial_number != SCarg->serial_number_at_timeout)) { | |||
1287 | printk("%s: reset, pid %ld, reset not running.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCarg->pid); | |||
1288 | return SCSI_RESET_NOT_RUNNING5; | |||
1289 | } | |||
1290 | ||||
1291 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->in_reset) { | |||
1292 | printk("%s: reset, exit, already in reset.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1293 | return SCSI_RESET_ERROR6; | |||
1294 | } | |||
1295 | ||||
1296 | if (wait_on_busy(sh[j]->io_port, MAXLOOP10000)) { | |||
1297 | printk("%s: reset, exit, timeout error.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1298 | return SCSI_RESET_ERROR6; | |||
1299 | } | |||
1300 | ||||
1301 | HD(j)((struct hostdata *) &sh[j]->hostdata)->retries = 0; | |||
1302 | ||||
1303 | for (c = 0; c <= sh[j]->max_channel; c++) | |||
1304 | for (k = 0; k < sh[j]->max_id; k++) { | |||
1305 | HD(j)((struct hostdata *) &sh[j]->hostdata)->target_redo[k][c] = TRUE1; | |||
1306 | HD(j)((struct hostdata *) &sh[j]->hostdata)->target_to[k][c] = 0; | |||
1307 | } | |||
1308 | ||||
1309 | for (i = 0; i < sh[j]->can_queue; i++) { | |||
1310 | ||||
1311 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == FREE0) continue; | |||
1312 | ||||
1313 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == LOCKED2) { | |||
1314 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1315 | printk("%s: reset, locked mbox %d forced free.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1316 | continue; | |||
1317 | } | |||
1318 | ||||
1319 | if (!(SCpnt = HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt)) | |||
1320 | panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1321 | ||||
1322 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == READY5 || HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == ABORTING6) { | |||
1323 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = ABORTING6; | |||
1324 | printk("%s: reset, mbox %d aborting, pid %ld.\n", | |||
1325 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->pid); | |||
1326 | } | |||
1327 | ||||
1328 | else { | |||
1329 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = IN_RESET3; | |||
1330 | printk("%s: reset, mbox %d in reset, pid %ld.\n", | |||
1331 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->pid); | |||
1332 | } | |||
1333 | ||||
1334 | if (SCpnt->host_scribble == NULL((void *) 0)) | |||
1335 | panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1336 | ||||
1337 | if (*(unsigned int *)SCpnt->host_scribble != i) | |||
1338 | panic("%s: reset, mbox %d, index mismatch.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1339 | ||||
1340 | if (SCpnt->scsi_done == NULL((void *) 0)) | |||
1341 | panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1342 | ||||
1343 | if (SCpnt == SCarg) arg_done = TRUE1; | |||
1344 | } | |||
1345 | ||||
1346 | if (wait_on_busy(sh[j]->io_port, MAXLOOP10000)) { | |||
1347 | printk("%s: reset, cannot reset, timeout error.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1348 | return SCSI_RESET_ERROR6; | |||
1349 | } | |||
1350 | ||||
1351 | outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR)((__builtin_constant_p((sh[j]->io_port + 1)) && (sh [j]->io_port + 1) < 256) ? __outbc((0xc0),(sh[j]->io_port + 1)) : __outb((0xc0),(sh[j]->io_port + 1))); | |||
1352 | printk("%s: reset, board reset done, enabling interrupts.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1353 | ||||
1354 | #if defined(DEBUG_RESET) | |||
1355 | do_trace = TRUE1; | |||
1356 | #endif | |||
1357 | ||||
1358 | HD(j)((struct hostdata *) &sh[j]->hostdata)->in_reset = TRUE1; | |||
1359 | SPIN_UNLOCK | |||
1360 | IRQ_UNLOCK__asm__ __volatile__ ("sti": : :"memory"); | |||
1361 | time = jiffies; | |||
1362 | while ((jiffies - time) < (10 * HZ100) && limit++ < 200000) udelay(100L)(__builtin_constant_p(100L) ? __const_udelay((100L) * 0x10c6ul ) : __udelay(100L)); | |||
1363 | IRQ_LOCK__asm__ __volatile__ ("cli": : :"memory"); | |||
1364 | SPIN_LOCK | |||
1365 | printk("%s: reset, interrupts disabled, loops %d.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), limit); | |||
1366 | ||||
1367 | for (i = 0; i < sh[j]->can_queue; i++) { | |||
1368 | ||||
1369 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == IN_RESET3) { | |||
1370 | SCpnt = HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt; | |||
1371 | SCpnt->result = DID_RESET0x08 << 16; | |||
1372 | SCpnt->host_scribble = NULL((void *) 0); | |||
1373 | ||||
1374 | /* This mailbox is still waiting for its interrupt */ | |||
1375 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = LOCKED2; | |||
1376 | ||||
1377 | printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", | |||
1378 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->pid); | |||
1379 | } | |||
1380 | ||||
1381 | else if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == ABORTING6) { | |||
1382 | SCpnt = HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt; | |||
1383 | SCpnt->result = DID_RESET0x08 << 16; | |||
1384 | SCpnt->host_scribble = NULL((void *) 0); | |||
1385 | ||||
1386 | /* This mailbox was never queued to the adapter */ | |||
1387 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1388 | ||||
1389 | printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", | |||
1390 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->pid); | |||
1391 | } | |||
1392 | ||||
1393 | else | |||
1394 | ||||
1395 | /* Any other mailbox has already been set free by interrupt */ | |||
1396 | continue; | |||
1397 | ||||
1398 | SCpnt->scsi_done(SCpnt); | |||
1399 | IRQ_LOCK__asm__ __volatile__ ("cli": : :"memory"); | |||
1400 | } | |||
1401 | ||||
1402 | HD(j)((struct hostdata *) &sh[j]->hostdata)->in_reset = FALSE0; | |||
1403 | do_trace = FALSE0; | |||
1404 | ||||
1405 | if (arg_done) { | |||
1406 | printk("%s: reset, exit, success.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1407 | return SCSI_RESET_SUCCESS2; | |||
1408 | } | |||
1409 | else { | |||
1410 | printk("%s: reset, exit, wakeup.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1411 | return SCSI_RESET_PUNT1; | |||
1412 | } | |||
1413 | } | |||
1414 | ||||
1415 | int u14_34f_old_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) { | |||
1416 | int rtn; | |||
1417 | IRQ_FLAGSunsigned long irq_flags; | |||
1418 | ||||
1419 | IRQ_LOCK_SAVEdo {__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory"); __asm__ __volatile__ ("cli": : :"memory");} while (0); | |||
1420 | rtn = do_old_reset(SCarg); | |||
1421 | IRQ_UNLOCK_RESTOREdo {__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); | |||
1422 | return rtn; | |||
1423 | } | |||
1424 | ||||
1425 | #if LINUX_VERSION_CODE131108 >= LinuxVersionCode(2,1,101)(((2)<<16)+((1)<<8)+(101)) | |||
1426 | ||||
1427 | static inlineinline __attribute__((always_inline)) int do_reset(Scsi_Cmnd *SCarg) { | |||
1428 | unsigned int i, j, time, k, c, limit = 0; | |||
1429 | int arg_done = FALSE0; | |||
1430 | Scsi_Cmnd *SCpnt; | |||
1431 | ||||
1432 | j = ((struct hostdata *) SCarg->host->hostdata)->board_number; | |||
1433 | printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n", | |||
1434 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCarg->channel, SCarg->target, SCarg->lun, SCarg->pid); | |||
1435 | ||||
1436 | if (SCarg->host_scribble == NULL((void *) 0)) | |||
1437 | printk("%s: reset, pid %ld inactive.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCarg->pid); | |||
1438 | ||||
1439 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->in_reset) { | |||
1440 | printk("%s: reset, exit, already in reset.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1441 | return FAILED; | |||
1442 | } | |||
1443 | ||||
1444 | if (wait_on_busy(sh[j]->io_port, MAXLOOP10000)) { | |||
1445 | printk("%s: reset, exit, timeout error.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1446 | return FAILED; | |||
1447 | } | |||
1448 | ||||
1449 | HD(j)((struct hostdata *) &sh[j]->hostdata)->retries = 0; | |||
1450 | ||||
1451 | for (c = 0; c <= sh[j]->max_channel; c++) | |||
1452 | for (k = 0; k < sh[j]->max_id; k++) { | |||
1453 | HD(j)((struct hostdata *) &sh[j]->hostdata)->target_redo[k][c] = TRUE1; | |||
1454 | HD(j)((struct hostdata *) &sh[j]->hostdata)->target_to[k][c] = 0; | |||
1455 | } | |||
1456 | ||||
1457 | for (i = 0; i < sh[j]->can_queue; i++) { | |||
1458 | ||||
1459 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == FREE0) continue; | |||
1460 | ||||
1461 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == LOCKED2) { | |||
1462 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1463 | printk("%s: reset, locked mbox %d forced free.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1464 | continue; | |||
1465 | } | |||
1466 | ||||
1467 | if (!(SCpnt = HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt)) | |||
1468 | panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1469 | ||||
1470 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == READY5 || HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == ABORTING6) { | |||
1471 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = ABORTING6; | |||
1472 | printk("%s: reset, mbox %d aborting, pid %ld.\n", | |||
1473 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->pid); | |||
1474 | } | |||
1475 | ||||
1476 | else { | |||
1477 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = IN_RESET3; | |||
1478 | printk("%s: reset, mbox %d in reset, pid %ld.\n", | |||
1479 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->pid); | |||
1480 | } | |||
1481 | ||||
1482 | if (SCpnt->host_scribble == NULL((void *) 0)) | |||
1483 | panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1484 | ||||
1485 | if (*(unsigned int *)SCpnt->host_scribble != i) | |||
1486 | panic("%s: reset, mbox %d, index mismatch.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1487 | ||||
1488 | if (SCpnt->scsi_done == NULL((void *) 0)) | |||
1489 | panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1490 | ||||
1491 | if (SCpnt == SCarg) arg_done = TRUE1; | |||
1492 | } | |||
1493 | ||||
1494 | if (wait_on_busy(sh[j]->io_port, MAXLOOP10000)) { | |||
1495 | printk("%s: reset, cannot reset, timeout error.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1496 | return FAILED; | |||
1497 | } | |||
1498 | ||||
1499 | outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR)((__builtin_constant_p((sh[j]->io_port + 1)) && (sh [j]->io_port + 1) < 256) ? __outbc((0xc0),(sh[j]->io_port + 1)) : __outb((0xc0),(sh[j]->io_port + 1))); | |||
1500 | printk("%s: reset, board reset done, enabling interrupts.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1501 | ||||
1502 | #if defined(DEBUG_RESET) | |||
1503 | do_trace = TRUE1; | |||
1504 | #endif | |||
1505 | ||||
1506 | HD(j)((struct hostdata *) &sh[j]->hostdata)->in_reset = TRUE1; | |||
1507 | SPIN_UNLOCK | |||
1508 | IRQ_UNLOCK__asm__ __volatile__ ("sti": : :"memory"); | |||
1509 | time = jiffies; | |||
1510 | while ((jiffies - time) < (10 * HZ100) && limit++ < 200000) udelay(100L)(__builtin_constant_p(100L) ? __const_udelay((100L) * 0x10c6ul ) : __udelay(100L)); | |||
1511 | IRQ_LOCK__asm__ __volatile__ ("cli": : :"memory"); | |||
1512 | SPIN_LOCK | |||
1513 | printk("%s: reset, interrupts disabled, loops %d.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), limit); | |||
1514 | ||||
1515 | for (i = 0; i < sh[j]->can_queue; i++) { | |||
1516 | ||||
1517 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == IN_RESET3) { | |||
1518 | SCpnt = HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt; | |||
1519 | SCpnt->result = DID_RESET0x08 << 16; | |||
1520 | SCpnt->host_scribble = NULL((void *) 0); | |||
1521 | ||||
1522 | /* This mailbox is still waiting for its interrupt */ | |||
1523 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = LOCKED2; | |||
1524 | ||||
1525 | printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", | |||
1526 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->pid); | |||
1527 | } | |||
1528 | ||||
1529 | else if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == ABORTING6) { | |||
1530 | SCpnt = HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i].SCpnt; | |||
1531 | SCpnt->result = DID_RESET0x08 << 16; | |||
1532 | SCpnt->host_scribble = NULL((void *) 0); | |||
1533 | ||||
1534 | /* This mailbox was never queued to the adapter */ | |||
1535 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1536 | ||||
1537 | printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", | |||
1538 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->pid); | |||
1539 | } | |||
1540 | ||||
1541 | else | |||
1542 | ||||
1543 | /* Any other mailbox has already been set free by interrupt */ | |||
1544 | continue; | |||
1545 | ||||
1546 | SCpnt->scsi_done(SCpnt); | |||
1547 | IRQ_LOCK__asm__ __volatile__ ("cli": : :"memory"); | |||
1548 | } | |||
1549 | ||||
1550 | HD(j)((struct hostdata *) &sh[j]->hostdata)->in_reset = FALSE0; | |||
1551 | do_trace = FALSE0; | |||
1552 | ||||
1553 | if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), SCarg->pid); | |||
1554 | else printk("%s: reset, exit.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name )); | |||
1555 | ||||
1556 | return SUCCESS; | |||
1557 | } | |||
1558 | ||||
1559 | int u14_34f_reset(Scsi_Cmnd *SCarg) { | |||
1560 | ||||
1561 | return do_reset(SCarg); | |||
1562 | } | |||
1563 | ||||
1564 | #endif /* new_eh_code */ | |||
1565 | ||||
1566 | int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) { | |||
1567 | unsigned int j = 0; | |||
1568 | int size = disk->capacity; | |||
1569 | ||||
1570 | dkinfo[0] = HD(j)((struct hostdata *) &sh[j]->hostdata)->heads; | |||
1571 | dkinfo[1] = HD(j)((struct hostdata *) &sh[j]->hostdata)->sectors; | |||
1572 | dkinfo[2] = size / (HD(j)((struct hostdata *) &sh[j]->hostdata)->heads * HD(j)((struct hostdata *) &sh[j]->hostdata)->sectors); | |||
1573 | ||||
1574 | if (ext_tran && (scsicam_bios_param(disk, dev, dkinfo) < 0)) { | |||
1575 | dkinfo[0] = 255; | |||
1576 | dkinfo[1] = 63; | |||
1577 | dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); | |||
1578 | } | |||
1579 | ||||
1580 | #if defined (DEBUG_GEOMETRY) | |||
1581 | printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name, | |||
1582 | dkinfo[0], dkinfo[1], dkinfo[2]); | |||
1583 | #endif | |||
1584 | ||||
1585 | return FALSE0; | |||
1586 | } | |||
1587 | ||||
1588 | static void sort(unsigned long sk[], unsigned int da[], unsigned int n, | |||
1589 | unsigned int rev) { | |||
1590 | unsigned int i, j, k, y; | |||
1591 | unsigned long x; | |||
1592 | ||||
1593 | for (i = 0; i < n - 1; i++) { | |||
1594 | k = i; | |||
1595 | ||||
1596 | for (j = k + 1; j < n; j++) | |||
1597 | if (rev) { | |||
1598 | if (sk[j] > sk[k]) k = j; | |||
1599 | } | |||
1600 | else { | |||
1601 | if (sk[j] < sk[k]) k = j; | |||
1602 | } | |||
1603 | ||||
1604 | if (k != i) { | |||
1605 | x = sk[k]; sk[k] = sk[i]; sk[i] = x; | |||
1606 | y = da[k]; da[k] = da[i]; da[i] = y; | |||
1607 | } | |||
1608 | } | |||
1609 | ||||
1610 | return; | |||
1611 | } | |||
1612 | ||||
1613 | static inlineinline __attribute__((always_inline)) int reorder(unsigned int j, unsigned long cursec, | |||
1614 | unsigned int ihdlr, unsigned int il[], unsigned int n_ready) { | |||
1615 | Scsi_Cmnd *SCpnt; | |||
1616 | struct mscp *cpp; | |||
1617 | unsigned int k, n; | |||
1618 | unsigned int rev = FALSE0, s = TRUE1, r = TRUE1; | |||
1619 | unsigned int input_only = TRUE1, overlap = FALSE0; | |||
1620 | unsigned long sl[n_ready], pl[n_ready], ll[n_ready]; | |||
1621 | unsigned long maxsec = 0, minsec = ULONG_MAX(~0UL), seek = 0, iseek = 0; | |||
1622 | unsigned long ioseek = 0; | |||
1623 | ||||
1624 | static unsigned int flushcount = 0, batchcount = 0, sortcount = 0; | |||
1625 | static unsigned int readycount = 0, ovlcount = 0, inputcount = 0; | |||
1626 | static unsigned int readysorted = 0, revcount = 0; | |||
1627 | static unsigned long seeksorted = 0, seeknosort = 0; | |||
1628 | ||||
1629 | if (link_statistics && !(++flushcount % link_statistics)) | |||
1630 | printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\ | |||
1631 | " av %ldK as %ldK.\n", flushcount, batchcount, inputcount, | |||
1632 | ovlcount, readycount, readysorted, sortcount, revcount, | |||
1633 | seeknosort / (readycount + 1), | |||
1634 | seeksorted / (readycount + 1)); | |||
1635 | ||||
1636 | if (n_ready <= 1) return FALSE0; | |||
1637 | ||||
1638 | for (n = 0; n < n_ready; n++) { | |||
1639 | k = il[n]; cpp = &HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[k]; SCpnt = cpp->SCpnt; | |||
1640 | ||||
1641 | if (!(cpp->xdir == DTD_IN0x1)) input_only = FALSE0; | |||
1642 | ||||
1643 | if (SCpnt->request.sector < minsec) minsec = SCpnt->request.sector; | |||
1644 | if (SCpnt->request.sector > maxsec) maxsec = SCpnt->request.sector; | |||
1645 | ||||
1646 | sl[n] = SCpnt->request.sector; | |||
1647 | ioseek += SCpnt->request.nr_sectors; | |||
1648 | ||||
1649 | if (!n) continue; | |||
1650 | ||||
1651 | if (sl[n] < sl[n - 1]) s = FALSE0; | |||
1652 | if (sl[n] > sl[n - 1]) r = FALSE0; | |||
1653 | ||||
1654 | if (link_statistics) { | |||
1655 | if (sl[n] > sl[n - 1]) | |||
1656 | seek += sl[n] - sl[n - 1]; | |||
1657 | else | |||
1658 | seek += sl[n - 1] - sl[n]; | |||
1659 | } | |||
1660 | ||||
1661 | } | |||
1662 | ||||
1663 | if (link_statistics) { | |||
1664 | if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec; | |||
1665 | } | |||
1666 | ||||
1667 | if (cursec > ((maxsec + minsec) / 2)) rev = TRUE1; | |||
1668 | ||||
1669 | if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE0; | |||
1670 | ||||
1671 | if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev); | |||
1672 | ||||
1673 | if (!input_only) for (n = 0; n < n_ready; n++) { | |||
1674 | k = il[n]; cpp = &HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[k]; SCpnt = cpp->SCpnt; | |||
1675 | ll[n] = SCpnt->request.nr_sectors; pl[n] = SCpnt->pid; | |||
1676 | ||||
1677 | if (!n) continue; | |||
1678 | ||||
1679 | if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n])) | |||
1680 | || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE1; | |||
1681 | } | |||
1682 | ||||
1683 | if (overlap) sort(pl, il, n_ready, FALSE0); | |||
1684 | ||||
1685 | if (link_statistics) { | |||
1686 | if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec; | |||
1687 | batchcount++; readycount += n_ready, seeknosort += seek / 1024; | |||
1688 | if (input_only) inputcount++; | |||
1689 | if (overlap) { ovlcount++; seeksorted += iseek / 1024; } | |||
1690 | else seeksorted += (iseek + maxsec - minsec) / 1024; | |||
1691 | if (rev && !r) { revcount++; readysorted += n_ready; } | |||
1692 | if (!rev && !s) { sortcount++; readysorted += n_ready; } | |||
1693 | } | |||
1694 | ||||
1695 | #if defined(DEBUG_LINKED_COMMANDS) | |||
1696 | if (link_statistics && (overlap || !(flushcount % link_statistics))) | |||
1697 | for (n = 0; n < n_ready; n++) { | |||
1698 | k = il[n]; cpp = &HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[k]; SCpnt = cpp->SCpnt; | |||
1699 | printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\ | |||
1700 | " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", | |||
1701 | (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, | |||
1702 | SCpnt->lun, SCpnt->pid, k, flushcount, n_ready, | |||
1703 | SCpnt->request.sector, SCpnt->request.nr_sectors, cursec, | |||
1704 | YESNO(s)((s) ? 'y' : 'n'), YESNO(r)((r) ? 'y' : 'n'), YESNO(rev)((rev) ? 'y' : 'n'), YESNO(input_only)((input_only) ? 'y' : 'n'), | |||
1705 | YESNO(overlap)((overlap) ? 'y' : 'n'), cpp->xdir); | |||
1706 | } | |||
1707 | #endif | |||
1708 | return overlap; | |||
1709 | } | |||
1710 | ||||
1711 | static void flush_dev(Scsi_Device *dev, unsigned long cursec, unsigned int j, | |||
1712 | unsigned int ihdlr) { | |||
1713 | Scsi_Cmnd *SCpnt; | |||
1714 | struct mscp *cpp; | |||
1715 | unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES16]; | |||
1716 | ||||
1717 | for (k = 0; k < sh[j]->can_queue; k++) { | |||
1718 | ||||
1719 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[k] != READY5 && HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[k] != IN_USE1) continue; | |||
1720 | ||||
1721 | cpp = &HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[k]; SCpnt = cpp->SCpnt; | |||
1722 | ||||
1723 | if (SCpnt->device != dev) continue; | |||
1724 | ||||
1725 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[k] == IN_USE1) return; | |||
1726 | ||||
1727 | il[n_ready++] = k; | |||
1728 | } | |||
1729 | ||||
1730 | if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1; | |||
1731 | ||||
1732 | for (n = 0; n < n_ready; n++) { | |||
1733 | k = il[n]; cpp = &HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[k]; SCpnt = cpp->SCpnt; | |||
1734 | ||||
1735 | if (wait_on_busy(sh[j]->io_port, MAXLOOP10000)) { | |||
1736 | printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\ | |||
1737 | " busy, will abort.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), (ihdlr ? "ihdlr" : "qcomm"), | |||
1738 | SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, k); | |||
1739 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[k] = ABORTING6; | |||
1740 | continue; | |||
1741 | } | |||
1742 | ||||
1743 | outl(V2DEV(cpp), sh[j]->io_port + REG_OGM)((__builtin_constant_p((sh[j]->io_port + 8)) && (sh [j]->io_port + 8) < 256) ? __outlc((((cpp) ? (virt_to_phys ((void *)cpp)) : 0)),(sh[j]->io_port + 8)) : __outl((((cpp ) ? (virt_to_phys((void *)cpp)) : 0)),(sh[j]->io_port + 8) )); | |||
1744 | outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR)((__builtin_constant_p((sh[j]->io_port + 1)) && (sh [j]->io_port + 1) < 256) ? __outbc((0x01),(sh[j]->io_port + 1)) : __outb((0x01),(sh[j]->io_port + 1))); | |||
1745 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[k] = IN_USE1; | |||
1746 | } | |||
1747 | ||||
1748 | } | |||
1749 | ||||
1750 | static inlineinline __attribute__((always_inline)) void ihdlr(int irq, unsigned int j) { | |||
1751 | Scsi_Cmnd *SCpnt; | |||
1752 | unsigned int i, k, c, status, tstatus, reg, ret; | |||
1753 | struct mscp *spp, *cpp; | |||
1754 | ||||
1755 | if (sh[j]->irq != irq) | |||
1756 | panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), irq, sh[j]->irq); | |||
1757 | ||||
1758 | /* Check if this board need to be serviced */ | |||
1759 | if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)((__builtin_constant_p((sh[j]->io_port + 3)) && (sh [j]->io_port + 3) < 256) ? __inbc(sh[j]->io_port + 3 ) : __inb(sh[j]->io_port + 3))) & IRQ_ASSERTED0x01)) return; | |||
1760 | ||||
1761 | HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount++; | |||
1762 | ||||
1763 | if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), irq, | |||
1764 | HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount); | |||
1765 | ||||
1766 | /* Check if this board is still busy */ | |||
1767 | if (wait_on_busy(sh[j]->io_port, 20 * MAXLOOP10000)) { | |||
1768 | outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR)((__builtin_constant_p((sh[j]->io_port + 3)) && (sh [j]->io_port + 3) < 256) ? __outbc((0x01),(sh[j]->io_port + 3)) : __outb((0x01),(sh[j]->io_port + 3))); | |||
1769 | printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", | |||
1770 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), irq, reg, HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount); | |||
1771 | return; | |||
1772 | } | |||
1773 | ||||
1774 | ret = inl(sh[j]->io_port + REG_ICM)((__builtin_constant_p((sh[j]->io_port + 12)) && ( sh[j]->io_port + 12) < 256) ? __inlc(sh[j]->io_port + 12) : __inl(sh[j]->io_port + 12)); | |||
1775 | spp = (struct mscp *)DEV2V(ret)((ret) ? (phys_to_virt((unsigned long)ret)) : 0); | |||
1776 | cpp = spp; | |||
1777 | ||||
1778 | /* Clear interrupt pending flag */ | |||
1779 | outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR)((__builtin_constant_p((sh[j]->io_port + 3)) && (sh [j]->io_port + 3) < 256) ? __outbc((0x01),(sh[j]->io_port + 3)) : __outb((0x01),(sh[j]->io_port + 3))); | |||
1780 | ||||
1781 | #if defined(DEBUG_GENERATE_ABORTS) | |||
1782 | if ((HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount > 500) && ((HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount % 500) < 3)) return; | |||
1783 | #endif | |||
1784 | ||||
1785 | /* Find the mailbox to be serviced on this board */ | |||
1786 | i = cpp - HD(j)((struct hostdata *) &sh[j]->hostdata)->cp; | |||
1787 | ||||
1788 | if (cpp < HD(j)((struct hostdata *) &sh[j]->hostdata)->cp || cpp >= HD(j)((struct hostdata *) &sh[j]->hostdata)->cp + sh[j]->can_queue | |||
1789 | || i >= sh[j]->can_queue) | |||
1790 | panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), | |||
1791 | (void *)ret, HD(j)((struct hostdata *) &sh[j]->hostdata)->cp); | |||
1792 | ||||
1793 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == IGNORE4) { | |||
1794 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1795 | return; | |||
1796 | } | |||
1797 | else if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == LOCKED2) { | |||
1798 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1799 | printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, | |||
1800 | HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount); | |||
1801 | return; | |||
1802 | } | |||
1803 | else if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == FREE0) { | |||
1804 | printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, | |||
1805 | HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount); | |||
1806 | return; | |||
1807 | } | |||
1808 | else if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] == IN_RESET3) | |||
1809 | printk("%s: ihdlr, mbox %d is in reset.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1810 | else if (HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] != IN_USE1) | |||
1811 | panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n", | |||
1812 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i]); | |||
1813 | ||||
1814 | HD(j)((struct hostdata *) &sh[j]->hostdata)->cp_stat[i] = FREE0; | |||
1815 | SCpnt = cpp->SCpnt; | |||
1816 | ||||
1817 | if (SCpnt == NULL((void *) 0)) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i); | |||
1818 | ||||
1819 | if (SCpnt->host_scribble == NULL((void *) 0)) | |||
1820 | panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, | |||
1821 | SCpnt->pid, SCpnt); | |||
1822 | ||||
1823 | if (*(unsigned int *)SCpnt->host_scribble != i) | |||
1824 | panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", | |||
1825 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble); | |||
1826 | ||||
1827 | if (linked_comm && SCpnt->device->queue_depth > 2 | |||
1828 | && TLDEV(SCpnt->device->type)((SCpnt->device->type) == 0x00 || (SCpnt->device-> type) == 0x05)) | |||
1829 | flush_dev(SCpnt->device, SCpnt->request.sector, j, TRUE1); | |||
1830 | ||||
1831 | tstatus = status_byte(spp->target_status)(((spp->target_status) >> 1) & 0x1f); | |||
1832 | ||||
1833 | #if defined(DEBUG_GENERATE_ERRORS) | |||
1834 | if ((HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount > 500) && ((HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount % 200) < 2)) | |||
1835 | spp->adapter_status = 0x01; | |||
1836 | #endif | |||
1837 | ||||
1838 | switch (spp->adapter_status) { | |||
1839 | case ASOK0x00: /* status OK */ | |||
1840 | ||||
1841 | /* Forces a reset if a disk drive keeps returning BUSY */ | |||
1842 | if (tstatus == BUSY0x04 && SCpnt->device->type != TYPE_TAPE0x01) | |||
1843 | status = DID_ERROR0x07 << 16; | |||
1844 | ||||
1845 | /* If there was a bus reset, redo operation on each target */ | |||
1846 | else if (tstatus != GOOD0x00 && SCpnt->device->type == TYPE_DISK0x00 | |||
1847 | && HD(j)((struct hostdata *) &sh[j]->hostdata)->target_redo[SCpnt->target][SCpnt->channel]) | |||
1848 | status = DID_BUS_BUSY0x02 << 16; | |||
1849 | ||||
1850 | /* Works around a flaw in scsi.c */ | |||
1851 | else if (tstatus == CHECK_CONDITION0x01 | |||
1852 | && SCpnt->device->type == TYPE_DISK0x00 | |||
1853 | && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR0x01) | |||
1854 | status = DID_BUS_BUSY0x02 << 16; | |||
1855 | ||||
1856 | else | |||
1857 | status = DID_OK0x00 << 16; | |||
1858 | ||||
1859 | if (tstatus == GOOD0x00) | |||
1860 | HD(j)((struct hostdata *) &sh[j]->hostdata)->target_redo[SCpnt->target][SCpnt->channel] = FALSE0; | |||
1861 | ||||
1862 | if (spp->target_status && SCpnt->device->type == TYPE_DISK0x00) | |||
1863 | printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\ | |||
1864 | "target_status 0x%x, sense key 0x%x.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), | |||
1865 | SCpnt->channel, SCpnt->target, SCpnt->lun, | |||
1866 | SCpnt->pid, spp->target_status, | |||
1867 | SCpnt->sense_buffer[2]); | |||
1868 | ||||
1869 | HD(j)((struct hostdata *) &sh[j]->hostdata)->target_to[SCpnt->target][SCpnt->channel] = 0; | |||
1870 | ||||
1871 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->last_retried_pid == SCpnt->pid) HD(j)((struct hostdata *) &sh[j]->hostdata)->retries = 0; | |||
1872 | ||||
1873 | break; | |||
1874 | case ASST0x91: /* Selection Time Out */ | |||
1875 | ||||
1876 | if (HD(j)((struct hostdata *) &sh[j]->hostdata)->target_to[SCpnt->target][SCpnt->channel] > 1) | |||
1877 | status = DID_ERROR0x07 << 16; | |||
1878 | else { | |||
1879 | status = DID_TIME_OUT0x03 << 16; | |||
1880 | HD(j)((struct hostdata *) &sh[j]->hostdata)->target_to[SCpnt->target][SCpnt->channel]++; | |||
1881 | } | |||
1882 | ||||
1883 | break; | |||
1884 | ||||
1885 | /* Perform a limited number of internal retries */ | |||
1886 | case 0x93: /* Unexpected bus free */ | |||
1887 | case 0x94: /* Target bus phase sequence failure */ | |||
1888 | case 0x96: /* Illegal SCSI command */ | |||
1889 | case 0xa3: /* SCSI bus reset error */ | |||
1890 | ||||
1891 | for (c = 0; c <= sh[j]->max_channel; c++) | |||
1892 | for (k = 0; k < sh[j]->max_id; k++) | |||
1893 | HD(j)((struct hostdata *) &sh[j]->hostdata)->target_redo[k][c] = TRUE1; | |||
1894 | ||||
1895 | ||||
1896 | case 0x92: /* Data over/under-run */ | |||
1897 | ||||
1898 | if (SCpnt->device->type != TYPE_TAPE0x01 | |||
1899 | && HD(j)((struct hostdata *) &sh[j]->hostdata)->retries < MAX_INTERNAL_RETRIES64) { | |||
1900 | ||||
1901 | #if defined(DID_SOFT_ERROR) | |||
1902 | status = DID_SOFT_ERROR << 16; | |||
1903 | #else | |||
1904 | status = DID_BUS_BUSY0x02 << 16; | |||
1905 | #endif | |||
1906 | ||||
1907 | HD(j)((struct hostdata *) &sh[j]->hostdata)->retries++; | |||
1908 | HD(j)((struct hostdata *) &sh[j]->hostdata)->last_retried_pid = SCpnt->pid; | |||
1909 | } | |||
1910 | else | |||
1911 | status = DID_ERROR0x07 << 16; | |||
1912 | ||||
1913 | break; | |||
1914 | case 0x01: /* Invalid command */ | |||
1915 | case 0x02: /* Invalid parameters */ | |||
1916 | case 0x03: /* Invalid data list */ | |||
1917 | case 0x84: /* SCSI bus abort error */ | |||
1918 | case 0x9b: /* Auto request sense error */ | |||
1919 | case 0x9f: /* Unexpected command complete message error */ | |||
1920 | case 0xff: /* Invalid parameter in the S/G list */ | |||
1921 | default: | |||
1922 | status = DID_ERROR0x07 << 16; | |||
1923 | break; | |||
1924 | } | |||
1925 | ||||
1926 | SCpnt->result = status | spp->target_status; | |||
1927 | ||||
1928 | #if defined(DEBUG_INTERRUPT) | |||
1929 | if (SCpnt->result || do_trace) | |||
1930 | #else | |||
1931 | if ((spp->adapter_status != ASOK0x00 && HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount > 1000) || | |||
1932 | (spp->adapter_status != ASOK0x00 && | |||
1933 | spp->adapter_status != ASST0x91 && HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount <= 1000) || | |||
1934 | do_trace || msg_byte(spp->target_status)(((spp->target_status) >> 8) & 0xff)) | |||
1935 | #endif | |||
1936 | printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\ | |||
1937 | " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n", | |||
1938 | BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), i, spp->adapter_status, spp->target_status, | |||
1939 | SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid, | |||
1940 | reg, HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount); | |||
1941 | ||||
1942 | /* Set the command state to inactive */ | |||
1943 | SCpnt->host_scribble = NULL((void *) 0); | |||
1944 | ||||
1945 | SCpnt->scsi_done(SCpnt); | |||
1946 | ||||
1947 | if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j)(((struct hostdata *) &sh[j]->hostdata)->board_name ), irq, | |||
1948 | HD(j)((struct hostdata *) &sh[j]->hostdata)->iocount); | |||
1949 | ||||
1950 | return; | |||
1951 | } | |||
1952 | ||||
1953 | static void do_interrupt_handler(int irq, void *shap, struct pt_regs *regs) { | |||
1954 | unsigned int j; | |||
1955 | IRQ_FLAGSunsigned long irq_flags; | |||
1956 | SPIN_FLAGS | |||
1957 | ||||
1958 | /* Check if the interrupt must be processed by this handler */ | |||
1959 | if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return; | |||
1960 | ||||
1961 | SPIN_LOCK_SAVE | |||
1962 | IRQ_LOCK_SAVEdo {__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory"); __asm__ __volatile__ ("cli": : :"memory");} while (0); | |||
1963 | ihdlr(irq, j); | |||
1964 | IRQ_UNLOCK_RESTOREdo {__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); | |||
1965 | SPIN_UNLOCK_RESTORE | |||
1966 | } | |||
1967 | ||||
1968 | int u14_34f_release(struct Scsi_Host *shpnt) { | |||
1969 | unsigned int i, j; | |||
1970 | IRQ_FLAGSunsigned long irq_flags; | |||
1971 | ||||
1972 | IRQ_LOCK_SAVEdo {__asm__ __volatile__("pushf ; pop %0" : "=r" (irq_flags): :"memory"); __asm__ __volatile__ ("cli": : :"memory");} while (0); | |||
1973 | ||||
1974 | for (j = 0; sh[j] != NULL((void *) 0) && sh[j] != shpnt; j++); | |||
1975 | ||||
1976 | if (sh[j] == NULL((void *) 0)) panic("%s: release, invalid Scsi_Host pointer.\n", | |||
1977 | driver_name); | |||
1978 | ||||
1979 | for (i = 0; i < sh[j]->can_queue; i++) | |||
1980 | if ((&HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i])->sglist) kfreelinux_kfree((&HD(j)((struct hostdata *) &sh[j]->hostdata)->cp[i])->sglist); | |||
1981 | ||||
1982 | free_irq(sh[j]->irq, &sha[j]); | |||
1983 | ||||
1984 | if (sh[j]->dma_channel != NO_DMA0xff) free_dma(sh[j]->dma_channel); | |||
1985 | ||||
1986 | release_region(sh[j]->io_port, sh[j]->n_io_port); | |||
1987 | scsi_unregister(sh[j]); | |||
1988 | IRQ_UNLOCK_RESTOREdo {__asm__ __volatile__("push %0 ; popf": :"g" (irq_flags):"memory" );} while (0); | |||
1989 | return FALSE0; | |||
1990 | } | |||
1991 | ||||
1992 | #if defined(MODULE) | |||
1993 | Scsi_Host_Template driver_template = ULTRASTOR_14_34F{ name: "UltraStor 14F/34F rev. " "4.33.00" " ", detect: u14_34f_detect , release: u14_34f_release, queuecommand: u14_34f_queuecommand , abort: u14_34f_old_abort, reset: u14_34f_old_reset, bios_param : u14_34f_biosparam, this_id: 7, unchecked_isa_dma: 1, use_clustering : 1 }; | |||
1994 | ||||
1995 | #include "scsi_module.c" | |||
1996 | #endif |