diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/ultrastor.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/ultrastor.c')
-rw-r--r-- | drivers/scsi/ultrastor.c | 1204 |
1 files changed, 1204 insertions, 0 deletions
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c new file mode 100644 index 000000000000..7484916fe2aa --- /dev/null +++ b/drivers/scsi/ultrastor.c | |||
@@ -0,0 +1,1204 @@ | |||
1 | /* | ||
2 | * ultrastor.c Copyright (C) 1992 David B. Gentzel | ||
3 | * Low-level SCSI driver for UltraStor 14F, 24F, and 34F | ||
4 | * by David B. Gentzel, Whitfield Software Services, Carnegie, PA | ||
5 | * (gentzel@nova.enet.dec.com) | ||
6 | * scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu) | ||
7 | * 24F and multiple command support by John F. Carr (jfc@athena.mit.edu) | ||
8 | * John's work modified by Caleb Epstein (cae@jpmorgan.com) and | ||
9 | * Eric Youngdale (ericy@cais.com). | ||
10 | * Thanks to UltraStor for providing the necessary documentation | ||
11 | * | ||
12 | * This is an old driver, for the 14F and 34F you should be using the | ||
13 | * u14-34f driver instead. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * TODO: | ||
18 | * 1. Find out why scatter/gather is limited to 16 requests per command. | ||
19 | * This is fixed, at least on the 24F, as of version 1.12 - CAE. | ||
20 | * 2. Look at command linking (mscp.command_link and | ||
21 | * mscp.command_link_id). (Does not work with many disks, | ||
22 | * and no performance increase. ERY). | ||
23 | * 3. Allow multiple adapters. | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * NOTES: | ||
28 | * The UltraStor 14F, 24F, and 34F are a family of intelligent, high | ||
29 | * performance SCSI-2 host adapters. They all support command queueing | ||
30 | * and scatter/gather I/O. Some of them can also emulate the standard | ||
31 | * WD1003 interface for use with OS's which don't support SCSI. Here | ||
32 | * is the scoop on the various models: | ||
33 | * 14F - ISA first-party DMA HA with floppy support and WD1003 emulation. | ||
34 | * 14N - ISA HA with floppy support. I think that this is a non-DMA | ||
35 | * HA. Nothing further known. | ||
36 | * 24F - EISA Bus Master HA with floppy support and WD1003 emulation. | ||
37 | * 34F - VL-Bus Bus Master HA with floppy support (no WD1003 emulation). | ||
38 | * | ||
39 | * The 14F, 24F, and 34F are supported by this driver. | ||
40 | * | ||
41 | * Places flagged with a triple question-mark are things which are either | ||
42 | * unfinished, questionable, or wrong. | ||
43 | */ | ||
44 | |||
45 | /* Changes from version 1.11 alpha to 1.12 | ||
46 | * | ||
47 | * Increased the size of the scatter-gather list to 33 entries for | ||
48 | * the 24F adapter (it was 16). I don't have the specs for the 14F | ||
49 | * or the 34F, so they may support larger s-g lists as well. | ||
50 | * | ||
51 | * Caleb Epstein <cae@jpmorgan.com> | ||
52 | */ | ||
53 | |||
54 | /* Changes from version 1.9 to 1.11 | ||
55 | * | ||
56 | * Patches to bring this driver up to speed with the default kernel | ||
57 | * driver which supports only the 14F and 34F adapters. This version | ||
58 | * should compile cleanly into 0.99.13, 0.99.12 and probably 0.99.11. | ||
59 | * | ||
60 | * Fixes from Eric Youngdale to fix a few possible race conditions and | ||
61 | * several problems with bit testing operations (insufficient | ||
62 | * parentheses). | ||
63 | * | ||
64 | * Removed the ultrastor_abort() and ultrastor_reset() functions | ||
65 | * (enclosed them in #if 0 / #endif). These functions, at least on | ||
66 | * the 24F, cause the SCSI bus to do odd things and generally lead to | ||
67 | * kernel panics and machine hangs. This is like the Adaptec code. | ||
68 | * | ||
69 | * Use check/snarf_region for 14f, 34f to avoid I/O space address conflicts. | ||
70 | */ | ||
71 | |||
72 | /* Changes from version 1.8 to version 1.9 | ||
73 | * | ||
74 | * 0.99.11 patches (cae@jpmorgan.com) */ | ||
75 | |||
76 | /* Changes from version 1.7 to version 1.8 | ||
77 | * | ||
78 | * Better error reporting. | ||
79 | */ | ||
80 | |||
81 | /* Changes from version 1.6 to version 1.7 | ||
82 | * | ||
83 | * Removed CSIR command code. | ||
84 | * | ||
85 | * Better race condition avoidance (xchgb function added). | ||
86 | * | ||
87 | * Set ICM and OGM status to zero at probe (24F) | ||
88 | * | ||
89 | * reset sends soft reset to UltraStor adapter | ||
90 | * | ||
91 | * reset adapter if adapter interrupts with an invalid MSCP address | ||
92 | * | ||
93 | * handle aborted command interrupt (24F) | ||
94 | * | ||
95 | */ | ||
96 | |||
97 | /* Changes from version 1.5 to version 1.6: | ||
98 | * | ||
99 | * Read MSCP address from ICM _before_ clearing the interrupt flag. | ||
100 | * This fixes a race condition. | ||
101 | */ | ||
102 | |||
103 | /* Changes from version 1.4 to version 1.5: | ||
104 | * | ||
105 | * Abort now calls done when multiple commands are enabled. | ||
106 | * | ||
107 | * Clear busy when aborted command finishes, not when abort is called. | ||
108 | * | ||
109 | * More debugging messages for aborts. | ||
110 | */ | ||
111 | |||
112 | /* Changes from version 1.3 to version 1.4: | ||
113 | * | ||
114 | * Enable automatic request of sense data on error (requires newer version | ||
115 | * of scsi.c to be useful). | ||
116 | * | ||
117 | * Fix PORT_OVERRIDE for 14F. | ||
118 | * | ||
119 | * Fix abort and reset to work properly (config.aborted wasn't cleared | ||
120 | * after it was tested, so after a command abort no further commands would | ||
121 | * work). | ||
122 | * | ||
123 | * Boot time test to enable SCSI bus reset (defaults to not allowing reset). | ||
124 | * | ||
125 | * Fix test for OGM busy -- the busy bit is in different places on the 24F. | ||
126 | * | ||
127 | * Release ICM slot by clearing first byte on 24F. | ||
128 | */ | ||
129 | |||
130 | #include <linux/module.h> | ||
131 | #include <linux/blkdev.h> | ||
132 | #include <linux/interrupt.h> | ||
133 | #include <linux/stddef.h> | ||
134 | #include <linux/string.h> | ||
135 | #include <linux/kernel.h> | ||
136 | #include <linux/ioport.h> | ||
137 | #include <linux/proc_fs.h> | ||
138 | #include <linux/spinlock.h> | ||
139 | #include <linux/stat.h> | ||
140 | #include <linux/bitops.h> | ||
141 | |||
142 | #include <asm/io.h> | ||
143 | #include <asm/system.h> | ||
144 | #include <asm/dma.h> | ||
145 | |||
146 | #define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */ | ||
147 | #include "scsi.h" | ||
148 | #include <scsi/scsi_host.h> | ||
149 | #include "ultrastor.h" | ||
150 | |||
151 | #define FALSE 0 | ||
152 | #define TRUE 1 | ||
153 | |||
154 | #ifndef ULTRASTOR_DEBUG | ||
155 | #define ULTRASTOR_DEBUG (UD_ABORT|UD_CSIR|UD_RESET) | ||
156 | #endif | ||
157 | |||
158 | #define VERSION "1.12" | ||
159 | |||
160 | #define PACKED __attribute__((packed)) | ||
161 | #define ALIGNED(x) __attribute__((aligned(x))) | ||
162 | |||
163 | |||
164 | /* The 14F uses an array of 4-byte ints for its scatter/gather list. | ||
165 | The data can be unaligned, but need not be. It's easier to give | ||
166 | the list normal alignment since it doesn't need to fit into a | ||
167 | packed structure. */ | ||
168 | |||
169 | typedef struct { | ||
170 | u32 address; | ||
171 | u32 num_bytes; | ||
172 | } ultrastor_sg_list; | ||
173 | |||
174 | |||
175 | /* MailBox SCSI Command Packet. Basic command structure for communicating | ||
176 | with controller. */ | ||
177 | struct mscp { | ||
178 | unsigned char opcode: 3; /* type of command */ | ||
179 | unsigned char xdir: 2; /* data transfer direction */ | ||
180 | unsigned char dcn: 1; /* disable disconnect */ | ||
181 | unsigned char ca: 1; /* use cache (if available) */ | ||
182 | unsigned char sg: 1; /* scatter/gather operation */ | ||
183 | unsigned char target_id: 3; /* target SCSI id */ | ||
184 | unsigned char ch_no: 2; /* SCSI channel (always 0 for 14f) */ | ||
185 | unsigned char lun: 3; /* logical unit number */ | ||
186 | unsigned int transfer_data PACKED; /* transfer data pointer */ | ||
187 | unsigned int transfer_data_length PACKED; /* length in bytes */ | ||
188 | unsigned int command_link PACKED; /* for linking command chains */ | ||
189 | unsigned char scsi_command_link_id; /* identifies command in chain */ | ||
190 | unsigned char number_of_sg_list; /* (if sg is set) 8 bytes per list */ | ||
191 | unsigned char length_of_sense_byte; | ||
192 | unsigned char length_of_scsi_cdbs; /* 6, 10, or 12 */ | ||
193 | unsigned char scsi_cdbs[12]; /* SCSI commands */ | ||
194 | unsigned char adapter_status; /* non-zero indicates HA error */ | ||
195 | unsigned char target_status; /* non-zero indicates target error */ | ||
196 | u32 sense_data PACKED; | ||
197 | /* The following fields are for software only. They are included in | ||
198 | the MSCP structure because they are associated with SCSI requests. */ | ||
199 | void (*done)(Scsi_Cmnd *); | ||
200 | Scsi_Cmnd *SCint; | ||
201 | ultrastor_sg_list sglist[ULTRASTOR_24F_MAX_SG]; /* use larger size for 24F */ | ||
202 | }; | ||
203 | |||
204 | |||
205 | /* Port addresses (relative to the base address) */ | ||
206 | #define U14F_PRODUCT_ID(port) ((port) + 0x4) | ||
207 | #define CONFIG(port) ((port) + 0x6) | ||
208 | |||
209 | /* Port addresses relative to the doorbell base address. */ | ||
210 | #define LCL_DOORBELL_MASK(port) ((port) + 0x0) | ||
211 | #define LCL_DOORBELL_INTR(port) ((port) + 0x1) | ||
212 | #define SYS_DOORBELL_MASK(port) ((port) + 0x2) | ||
213 | #define SYS_DOORBELL_INTR(port) ((port) + 0x3) | ||
214 | |||
215 | |||
216 | /* Used to store configuration info read from config i/o registers. Most of | ||
217 | this is not used yet, but might as well save it. | ||
218 | |||
219 | This structure also holds port addresses that are not at the same offset | ||
220 | on the 14F and 24F. | ||
221 | |||
222 | This structure holds all data that must be duplicated to support multiple | ||
223 | adapters. */ | ||
224 | |||
225 | static struct ultrastor_config | ||
226 | { | ||
227 | unsigned short port_address; /* base address of card */ | ||
228 | unsigned short doorbell_address; /* base address of doorbell CSRs */ | ||
229 | unsigned short ogm_address; /* base address of OGM */ | ||
230 | unsigned short icm_address; /* base address of ICM */ | ||
231 | const void *bios_segment; | ||
232 | unsigned char interrupt: 4; | ||
233 | unsigned char dma_channel: 3; | ||
234 | unsigned char bios_drive_number: 1; | ||
235 | unsigned char heads; | ||
236 | unsigned char sectors; | ||
237 | unsigned char ha_scsi_id: 3; | ||
238 | unsigned char subversion: 4; | ||
239 | unsigned char revision; | ||
240 | /* The slot number is used to distinguish the 24F (slot != 0) from | ||
241 | the 14F and 34F (slot == 0). */ | ||
242 | unsigned char slot; | ||
243 | |||
244 | #ifdef PRINT_U24F_VERSION | ||
245 | volatile int csir_done; | ||
246 | #endif | ||
247 | |||
248 | /* A pool of MSCP structures for this adapter, and a bitmask of | ||
249 | busy structures. (If ULTRASTOR_14F_MAX_CMDS == 1, a 1 byte | ||
250 | busy flag is used instead.) */ | ||
251 | |||
252 | #if ULTRASTOR_MAX_CMDS == 1 | ||
253 | unsigned char mscp_busy; | ||
254 | #else | ||
255 | unsigned long mscp_free; | ||
256 | #endif | ||
257 | volatile unsigned char aborted[ULTRASTOR_MAX_CMDS]; | ||
258 | struct mscp mscp[ULTRASTOR_MAX_CMDS]; | ||
259 | } config = {0}; | ||
260 | |||
261 | /* Set this to 1 to reset the SCSI bus on error. */ | ||
262 | static int ultrastor_bus_reset; | ||
263 | |||
264 | |||
265 | /* Allowed BIOS base addresses (NULL indicates reserved) */ | ||
266 | static const void *const bios_segment_table[8] = { | ||
267 | NULL, (void *)0xC4000, (void *)0xC8000, (void *)0xCC000, | ||
268 | (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000, | ||
269 | }; | ||
270 | |||
271 | /* Allowed IRQs for 14f */ | ||
272 | static const unsigned char interrupt_table_14f[4] = { 15, 14, 11, 10 }; | ||
273 | |||
274 | /* Allowed DMA channels for 14f (0 indicates reserved) */ | ||
275 | static const unsigned char dma_channel_table_14f[4] = { 5, 6, 7, 0 }; | ||
276 | |||
277 | /* Head/sector mappings allowed by 14f */ | ||
278 | static const struct { | ||
279 | unsigned char heads; | ||
280 | unsigned char sectors; | ||
281 | } mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 } }; | ||
282 | |||
283 | #ifndef PORT_OVERRIDE | ||
284 | /* ??? A probe of address 0x310 screws up NE2000 cards */ | ||
285 | static const unsigned short ultrastor_ports_14f[] = { | ||
286 | 0x330, 0x340, /*0x310,*/ 0x230, 0x240, 0x210, 0x130, 0x140, | ||
287 | }; | ||
288 | #endif | ||
289 | |||
290 | static void ultrastor_interrupt(int, void *, struct pt_regs *); | ||
291 | static irqreturn_t do_ultrastor_interrupt(int, void *, struct pt_regs *); | ||
292 | static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt); | ||
293 | |||
294 | |||
295 | /* Always called with host lock held */ | ||
296 | |||
297 | static inline int find_and_clear_bit_16(unsigned long *field) | ||
298 | { | ||
299 | int rv; | ||
300 | |||
301 | if (*field == 0) panic("No free mscp"); | ||
302 | asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b" | ||
303 | : "=&r" (rv), "=m" (*field) : "1" (*field)); | ||
304 | return rv; | ||
305 | } | ||
306 | |||
307 | /* This has been re-implemented with the help of Richard Earnshaw, | ||
308 | <rwe@pegasus.esprit.ec.org> and works with gcc-2.5.8 and gcc-2.6.0. | ||
309 | The instability noted by jfc below appears to be a bug in | ||
310 | gcc-2.5.x when compiling w/o optimization. --Caleb | ||
311 | |||
312 | This asm is fragile: it doesn't work without the casts and it may | ||
313 | not work without optimization. Maybe I should add a swap builtin | ||
314 | to gcc. --jfc */ | ||
315 | static inline unsigned char xchgb(unsigned char reg, | ||
316 | volatile unsigned char *mem) | ||
317 | { | ||
318 | __asm__ ("xchgb %0,%1" : "=q" (reg), "=m" (*mem) : "0" (reg)); | ||
319 | return reg; | ||
320 | } | ||
321 | |||
322 | #if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT) | ||
323 | |||
324 | /* Always called with the host lock held */ | ||
325 | static void log_ultrastor_abort(struct ultrastor_config *config, | ||
326 | int command) | ||
327 | { | ||
328 | static char fmt[80] = "abort %d (%x); MSCP free pool: %x;"; | ||
329 | int i; | ||
330 | |||
331 | for (i = 0; i < ULTRASTOR_MAX_CMDS; i++) | ||
332 | { | ||
333 | fmt[20 + i*2] = ' '; | ||
334 | if (! (config->mscp_free & (1 << i))) | ||
335 | fmt[21 + i*2] = '0' + config->mscp[i].target_id; | ||
336 | else | ||
337 | fmt[21 + i*2] = '-'; | ||
338 | } | ||
339 | fmt[20 + ULTRASTOR_MAX_CMDS * 2] = '\n'; | ||
340 | fmt[21 + ULTRASTOR_MAX_CMDS * 2] = 0; | ||
341 | printk(fmt, command, &config->mscp[command], config->mscp_free); | ||
342 | |||
343 | } | ||
344 | #endif | ||
345 | |||
346 | static int ultrastor_14f_detect(Scsi_Host_Template * tpnt) | ||
347 | { | ||
348 | size_t i; | ||
349 | unsigned char in_byte, version_byte = 0; | ||
350 | struct config_1 { | ||
351 | unsigned char bios_segment: 3; | ||
352 | unsigned char removable_disks_as_fixed: 1; | ||
353 | unsigned char interrupt: 2; | ||
354 | unsigned char dma_channel: 2; | ||
355 | } config_1; | ||
356 | struct config_2 { | ||
357 | unsigned char ha_scsi_id: 3; | ||
358 | unsigned char mapping_mode: 2; | ||
359 | unsigned char bios_drive_number: 1; | ||
360 | unsigned char tfr_port: 2; | ||
361 | } config_2; | ||
362 | |||
363 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
364 | printk("US14F: detect: called\n"); | ||
365 | #endif | ||
366 | |||
367 | /* If a 24F has already been configured, don't look for a 14F. */ | ||
368 | if (config.bios_segment) | ||
369 | return FALSE; | ||
370 | |||
371 | #ifdef PORT_OVERRIDE | ||
372 | if(!request_region(PORT_OVERRIDE, 0xc, "ultrastor")) { | ||
373 | printk("Ultrastor I/O space already in use\n"); | ||
374 | return FALSE; | ||
375 | }; | ||
376 | config.port_address = PORT_OVERRIDE; | ||
377 | #else | ||
378 | for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) { | ||
379 | if(!request_region(ultrastor_ports_14f[i], 0x0c, "ultrastor")) continue; | ||
380 | config.port_address = ultrastor_ports_14f[i]; | ||
381 | #endif | ||
382 | |||
383 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
384 | printk("US14F: detect: testing port address %03X\n", config.port_address); | ||
385 | #endif | ||
386 | |||
387 | in_byte = inb(U14F_PRODUCT_ID(config.port_address)); | ||
388 | if (in_byte != US14F_PRODUCT_ID_0) { | ||
389 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
390 | # ifdef PORT_OVERRIDE | ||
391 | printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte); | ||
392 | # else | ||
393 | printk("US14F: detect: no adapter at port %03X\n", config.port_address); | ||
394 | # endif | ||
395 | #endif | ||
396 | #ifdef PORT_OVERRIDE | ||
397 | goto out_release_port; | ||
398 | #else | ||
399 | release_region(config.port_address, 0x0c); | ||
400 | continue; | ||
401 | #endif | ||
402 | } | ||
403 | in_byte = inb(U14F_PRODUCT_ID(config.port_address) + 1); | ||
404 | /* Only upper nibble is significant for Product ID 1 */ | ||
405 | if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) { | ||
406 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
407 | # ifdef PORT_OVERRIDE | ||
408 | printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte); | ||
409 | # else | ||
410 | printk("US14F: detect: no adapter at port %03X\n", config.port_address); | ||
411 | # endif | ||
412 | #endif | ||
413 | #ifdef PORT_OVERRIDE | ||
414 | goto out_release_port; | ||
415 | #else | ||
416 | release_region(config.port_address, 0x0c); | ||
417 | continue; | ||
418 | #endif | ||
419 | } | ||
420 | version_byte = in_byte; | ||
421 | #ifndef PORT_OVERRIDE | ||
422 | break; | ||
423 | } | ||
424 | if (i == ARRAY_SIZE(ultrastor_ports_14f)) { | ||
425 | # if (ULTRASTOR_DEBUG & UD_DETECT) | ||
426 | printk("US14F: detect: no port address found!\n"); | ||
427 | # endif | ||
428 | /* all ports probed already released - we can just go straight out */ | ||
429 | return FALSE; | ||
430 | } | ||
431 | #endif | ||
432 | |||
433 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
434 | printk("US14F: detect: adapter found at port address %03X\n", | ||
435 | config.port_address); | ||
436 | #endif | ||
437 | |||
438 | /* Set local doorbell mask to disallow bus reset unless | ||
439 | ultrastor_bus_reset is true. */ | ||
440 | outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(config.port_address)); | ||
441 | |||
442 | /* All above tests passed, must be the right thing. Get some useful | ||
443 | info. */ | ||
444 | |||
445 | /* Register the I/O space that we use */ | ||
446 | |||
447 | *(char *)&config_1 = inb(CONFIG(config.port_address + 0)); | ||
448 | *(char *)&config_2 = inb(CONFIG(config.port_address + 1)); | ||
449 | config.bios_segment = bios_segment_table[config_1.bios_segment]; | ||
450 | config.doorbell_address = config.port_address; | ||
451 | config.ogm_address = config.port_address + 0x8; | ||
452 | config.icm_address = config.port_address + 0xC; | ||
453 | config.interrupt = interrupt_table_14f[config_1.interrupt]; | ||
454 | config.ha_scsi_id = config_2.ha_scsi_id; | ||
455 | config.heads = mapping_table[config_2.mapping_mode].heads; | ||
456 | config.sectors = mapping_table[config_2.mapping_mode].sectors; | ||
457 | config.bios_drive_number = config_2.bios_drive_number; | ||
458 | config.subversion = (version_byte & 0x0F); | ||
459 | if (config.subversion == U34F) | ||
460 | config.dma_channel = 0; | ||
461 | else | ||
462 | config.dma_channel = dma_channel_table_14f[config_1.dma_channel]; | ||
463 | |||
464 | if (!config.bios_segment) { | ||
465 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
466 | printk("US14F: detect: not detected.\n"); | ||
467 | #endif | ||
468 | goto out_release_port; | ||
469 | } | ||
470 | |||
471 | /* Final consistency check, verify previous info. */ | ||
472 | if (config.subversion != U34F) | ||
473 | if (!config.dma_channel || !(config_2.tfr_port & 0x2)) { | ||
474 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
475 | printk("US14F: detect: consistency check failed\n"); | ||
476 | #endif | ||
477 | goto out_release_port; | ||
478 | } | ||
479 | |||
480 | /* If we were TRULY paranoid, we could issue a host adapter inquiry | ||
481 | command here and verify the data returned. But frankly, I'm | ||
482 | exhausted! */ | ||
483 | |||
484 | /* Finally! Now I'm satisfied... */ | ||
485 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
486 | printk("US14F: detect: detect succeeded\n" | ||
487 | " Port address: %03X\n" | ||
488 | " BIOS segment: %05X\n" | ||
489 | " Interrupt: %u\n" | ||
490 | " DMA channel: %u\n" | ||
491 | " H/A SCSI ID: %u\n" | ||
492 | " Subversion: %u\n", | ||
493 | config.port_address, config.bios_segment, config.interrupt, | ||
494 | config.dma_channel, config.ha_scsi_id, config.subversion); | ||
495 | #endif | ||
496 | tpnt->this_id = config.ha_scsi_id; | ||
497 | tpnt->unchecked_isa_dma = (config.subversion != U34F); | ||
498 | |||
499 | #if ULTRASTOR_MAX_CMDS > 1 | ||
500 | config.mscp_free = ~0; | ||
501 | #endif | ||
502 | |||
503 | /* | ||
504 | * Brrr, &config.mscp[0].SCint->host) it is something magical.... | ||
505 | * XXX and FIXME | ||
506 | */ | ||
507 | if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", &config.mscp[0].SCint->device->host)) { | ||
508 | printk("Unable to allocate IRQ%u for UltraStor controller.\n", | ||
509 | config.interrupt); | ||
510 | goto out_release_port; | ||
511 | } | ||
512 | if (config.dma_channel && request_dma(config.dma_channel,"Ultrastor")) { | ||
513 | printk("Unable to allocate DMA channel %u for UltraStor controller.\n", | ||
514 | config.dma_channel); | ||
515 | free_irq(config.interrupt, NULL); | ||
516 | goto out_release_port; | ||
517 | } | ||
518 | tpnt->sg_tablesize = ULTRASTOR_14F_MAX_SG; | ||
519 | printk("UltraStor driver version" VERSION ". Using %d SG lists.\n", | ||
520 | ULTRASTOR_14F_MAX_SG); | ||
521 | |||
522 | return TRUE; | ||
523 | out_release_port: | ||
524 | release_region(config.port_address, 0x0c); | ||
525 | return FALSE; | ||
526 | } | ||
527 | |||
528 | static int ultrastor_24f_detect(Scsi_Host_Template * tpnt) | ||
529 | { | ||
530 | int i; | ||
531 | struct Scsi_Host * shpnt = NULL; | ||
532 | |||
533 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
534 | printk("US24F: detect"); | ||
535 | #endif | ||
536 | |||
537 | /* probe each EISA slot at slot address C80 */ | ||
538 | for (i = 1; i < 15; i++) | ||
539 | { | ||
540 | unsigned char config_1, config_2; | ||
541 | unsigned short addr = (i << 12) | ULTRASTOR_24F_PORT; | ||
542 | |||
543 | if (inb(addr) != US24F_PRODUCT_ID_0 && | ||
544 | inb(addr+1) != US24F_PRODUCT_ID_1 && | ||
545 | inb(addr+2) != US24F_PRODUCT_ID_2) | ||
546 | continue; | ||
547 | |||
548 | config.revision = inb(addr+3); | ||
549 | config.slot = i; | ||
550 | if (! (inb(addr+4) & 1)) | ||
551 | { | ||
552 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
553 | printk("U24F: found disabled card in slot %u\n", i); | ||
554 | #endif | ||
555 | continue; | ||
556 | } | ||
557 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
558 | printk("U24F: found card in slot %u\n", i); | ||
559 | #endif | ||
560 | config_1 = inb(addr + 5); | ||
561 | config.bios_segment = bios_segment_table[config_1 & 7]; | ||
562 | switch(config_1 >> 4) | ||
563 | { | ||
564 | case 1: | ||
565 | config.interrupt = 15; | ||
566 | break; | ||
567 | case 2: | ||
568 | config.interrupt = 14; | ||
569 | break; | ||
570 | case 4: | ||
571 | config.interrupt = 11; | ||
572 | break; | ||
573 | case 8: | ||
574 | config.interrupt = 10; | ||
575 | break; | ||
576 | default: | ||
577 | printk("U24F: invalid IRQ\n"); | ||
578 | return FALSE; | ||
579 | } | ||
580 | |||
581 | /* BIOS addr set */ | ||
582 | /* base port set */ | ||
583 | config.port_address = addr; | ||
584 | config.doorbell_address = addr + 12; | ||
585 | config.ogm_address = addr + 0x17; | ||
586 | config.icm_address = addr + 0x1C; | ||
587 | config_2 = inb(addr + 7); | ||
588 | config.ha_scsi_id = config_2 & 7; | ||
589 | config.heads = mapping_table[(config_2 >> 3) & 3].heads; | ||
590 | config.sectors = mapping_table[(config_2 >> 3) & 3].sectors; | ||
591 | #if (ULTRASTOR_DEBUG & UD_DETECT) | ||
592 | printk("US24F: detect: detect succeeded\n" | ||
593 | " Port address: %03X\n" | ||
594 | " BIOS segment: %05X\n" | ||
595 | " Interrupt: %u\n" | ||
596 | " H/A SCSI ID: %u\n", | ||
597 | config.port_address, config.bios_segment, | ||
598 | config.interrupt, config.ha_scsi_id); | ||
599 | #endif | ||
600 | tpnt->this_id = config.ha_scsi_id; | ||
601 | tpnt->unchecked_isa_dma = 0; | ||
602 | tpnt->sg_tablesize = ULTRASTOR_24F_MAX_SG; | ||
603 | |||
604 | shpnt = scsi_register(tpnt, 0); | ||
605 | if (!shpnt) { | ||
606 | printk(KERN_WARNING "(ultrastor:) Could not register scsi device. Aborting registration.\n"); | ||
607 | free_irq(config.interrupt, do_ultrastor_interrupt); | ||
608 | return FALSE; | ||
609 | } | ||
610 | |||
611 | if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", shpnt)) | ||
612 | { | ||
613 | printk("Unable to allocate IRQ%u for UltraStor controller.\n", | ||
614 | config.interrupt); | ||
615 | return FALSE; | ||
616 | } | ||
617 | |||
618 | shpnt->irq = config.interrupt; | ||
619 | shpnt->dma_channel = config.dma_channel; | ||
620 | shpnt->io_port = config.port_address; | ||
621 | |||
622 | #if ULTRASTOR_MAX_CMDS > 1 | ||
623 | config.mscp_free = ~0; | ||
624 | #endif | ||
625 | /* Mark ICM and OGM free */ | ||
626 | outb(0, addr + 0x16); | ||
627 | outb(0, addr + 0x1B); | ||
628 | |||
629 | /* Set local doorbell mask to disallow bus reset unless | ||
630 | ultrastor_bus_reset is true. */ | ||
631 | outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(addr+12)); | ||
632 | outb(0x02, SYS_DOORBELL_MASK(addr+12)); | ||
633 | printk("UltraStor driver version " VERSION ". Using %d SG lists.\n", | ||
634 | tpnt->sg_tablesize); | ||
635 | return TRUE; | ||
636 | } | ||
637 | return FALSE; | ||
638 | } | ||
639 | |||
640 | static int ultrastor_detect(Scsi_Host_Template * tpnt) | ||
641 | { | ||
642 | tpnt->proc_name = "ultrastor"; | ||
643 | return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt); | ||
644 | } | ||
645 | |||
646 | static int ultrastor_release(struct Scsi_Host *shost) | ||
647 | { | ||
648 | if (shost->irq) | ||
649 | free_irq(shost->irq, NULL); | ||
650 | if (shost->dma_channel != 0xff) | ||
651 | free_dma(shost->dma_channel); | ||
652 | if (shost->io_port && shost->n_io_port) | ||
653 | release_region(shost->io_port, shost->n_io_port); | ||
654 | scsi_unregister(shost); | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static const char *ultrastor_info(struct Scsi_Host * shpnt) | ||
659 | { | ||
660 | static char buf[64]; | ||
661 | |||
662 | if (config.slot) | ||
663 | sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u", | ||
664 | config.slot, config.interrupt); | ||
665 | else if (config.subversion) | ||
666 | sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u", | ||
667 | config.port_address, (int)config.bios_segment, | ||
668 | config.interrupt); | ||
669 | else | ||
670 | sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u", | ||
671 | config.port_address, (int)config.bios_segment, | ||
672 | config.interrupt, config.dma_channel); | ||
673 | return buf; | ||
674 | } | ||
675 | |||
676 | static inline void build_sg_list(struct mscp *mscp, Scsi_Cmnd *SCpnt) | ||
677 | { | ||
678 | struct scatterlist *sl; | ||
679 | long transfer_length = 0; | ||
680 | int i, max; | ||
681 | |||
682 | sl = (struct scatterlist *) SCpnt->request_buffer; | ||
683 | max = SCpnt->use_sg; | ||
684 | for (i = 0; i < max; i++) { | ||
685 | mscp->sglist[i].address = isa_page_to_bus(sl[i].page) + sl[i].offset; | ||
686 | mscp->sglist[i].num_bytes = sl[i].length; | ||
687 | transfer_length += sl[i].length; | ||
688 | } | ||
689 | mscp->number_of_sg_list = max; | ||
690 | mscp->transfer_data = isa_virt_to_bus(mscp->sglist); | ||
691 | /* ??? May not be necessary. Docs are unclear as to whether transfer | ||
692 | length field is ignored or whether it should be set to the total | ||
693 | number of bytes of the transfer. */ | ||
694 | mscp->transfer_data_length = transfer_length; | ||
695 | } | ||
696 | |||
697 | static int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) | ||
698 | { | ||
699 | struct mscp *my_mscp; | ||
700 | #if ULTRASTOR_MAX_CMDS > 1 | ||
701 | int mscp_index; | ||
702 | #endif | ||
703 | unsigned int status; | ||
704 | |||
705 | /* Next test is for debugging; "can't happen" */ | ||
706 | if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 1)) == 0) | ||
707 | panic("ultrastor_queuecommand: no free MSCP\n"); | ||
708 | mscp_index = find_and_clear_bit_16(&config.mscp_free); | ||
709 | |||
710 | /* Has the command been aborted? */ | ||
711 | if (xchgb(0xff, &config.aborted[mscp_index]) != 0) | ||
712 | { | ||
713 | status = DID_ABORT << 16; | ||
714 | goto aborted; | ||
715 | } | ||
716 | |||
717 | my_mscp = &config.mscp[mscp_index]; | ||
718 | |||
719 | *(unsigned char *)my_mscp = OP_SCSI | (DTD_SCSI << 3); | ||
720 | |||
721 | /* Tape drives don't work properly if the cache is used. The SCSI | ||
722 | READ command for a tape doesn't have a block offset, and the adapter | ||
723 | incorrectly assumes that all reads from the tape read the same | ||
724 | blocks. Results will depend on read buffer size and other disk | ||
725 | activity. | ||
726 | |||
727 | ??? Which other device types should never use the cache? */ | ||
728 | my_mscp->ca = SCpnt->device->type != TYPE_TAPE; | ||
729 | my_mscp->target_id = SCpnt->device->id; | ||
730 | my_mscp->ch_no = 0; | ||
731 | my_mscp->lun = SCpnt->device->lun; | ||
732 | if (SCpnt->use_sg) { | ||
733 | /* Set scatter/gather flag in SCSI command packet */ | ||
734 | my_mscp->sg = TRUE; | ||
735 | build_sg_list(my_mscp, SCpnt); | ||
736 | } else { | ||
737 | /* Unset scatter/gather flag in SCSI command packet */ | ||
738 | my_mscp->sg = FALSE; | ||
739 | my_mscp->transfer_data = isa_virt_to_bus(SCpnt->request_buffer); | ||
740 | my_mscp->transfer_data_length = SCpnt->request_bufflen; | ||
741 | } | ||
742 | my_mscp->command_link = 0; /*???*/ | ||
743 | my_mscp->scsi_command_link_id = 0; /*???*/ | ||
744 | my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer; | ||
745 | my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len; | ||
746 | memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs); | ||
747 | my_mscp->adapter_status = 0; | ||
748 | my_mscp->target_status = 0; | ||
749 | my_mscp->sense_data = isa_virt_to_bus(&SCpnt->sense_buffer); | ||
750 | my_mscp->done = done; | ||
751 | my_mscp->SCint = SCpnt; | ||
752 | SCpnt->host_scribble = (unsigned char *)my_mscp; | ||
753 | |||
754 | /* Find free OGM slot. On 24F, look for OGM status byte == 0. | ||
755 | On 14F and 34F, wait for local interrupt pending flag to clear. | ||
756 | |||
757 | FIXME: now we are using new_eh we should punt here and let the | ||
758 | midlayer sort it out */ | ||
759 | |||
760 | retry: | ||
761 | if (config.slot) | ||
762 | while (inb(config.ogm_address - 1) != 0 && config.aborted[mscp_index] == 0xff) | ||
763 | barrier(); | ||
764 | |||
765 | /* else??? */ | ||
766 | |||
767 | while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1)) && config.aborted[mscp_index] == 0xff) | ||
768 | barrier(); | ||
769 | |||
770 | /* To avoid race conditions, keep the code to write to the adapter | ||
771 | atomic. This simplifies the abort code. Right now the | ||
772 | scsi mid layer has the host_lock already held | ||
773 | */ | ||
774 | |||
775 | if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1)) | ||
776 | goto retry; | ||
777 | |||
778 | status = xchgb(0, &config.aborted[mscp_index]); | ||
779 | if (status != 0xff) { | ||
780 | |||
781 | #if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT) | ||
782 | printk("USx4F: queuecommand: aborted\n"); | ||
783 | #if ULTRASTOR_MAX_CMDS > 1 | ||
784 | log_ultrastor_abort(&config, mscp_index); | ||
785 | #endif | ||
786 | #endif | ||
787 | status <<= 16; | ||
788 | |||
789 | aborted: | ||
790 | set_bit(mscp_index, &config.mscp_free); | ||
791 | /* If the driver queues commands, call the done proc here. Otherwise | ||
792 | return an error. */ | ||
793 | #if ULTRASTOR_MAX_CMDS > 1 | ||
794 | SCpnt->result = status; | ||
795 | done(SCpnt); | ||
796 | return 0; | ||
797 | #else | ||
798 | return status; | ||
799 | #endif | ||
800 | } | ||
801 | |||
802 | /* Store pointer in OGM address bytes */ | ||
803 | outl(isa_virt_to_bus(my_mscp), config.ogm_address); | ||
804 | |||
805 | /* Issue OGM interrupt */ | ||
806 | if (config.slot) { | ||
807 | /* Write OGM command register on 24F */ | ||
808 | outb(1, config.ogm_address - 1); | ||
809 | outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address)); | ||
810 | } else { | ||
811 | outb(0x1, LCL_DOORBELL_INTR(config.doorbell_address)); | ||
812 | } | ||
813 | |||
814 | #if (ULTRASTOR_DEBUG & UD_COMMAND) | ||
815 | printk("USx4F: queuecommand: returning\n"); | ||
816 | #endif | ||
817 | |||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | /* This code must deal with 2 cases: | ||
822 | |||
823 | 1. The command has not been written to the OGM. In this case, set | ||
824 | the abort flag and return. | ||
825 | |||
826 | 2. The command has been written to the OGM and is stuck somewhere in | ||
827 | the adapter. | ||
828 | |||
829 | 2a. On a 24F, ask the adapter to abort the command. It will interrupt | ||
830 | when it does. | ||
831 | |||
832 | 2b. Call the command's done procedure. | ||
833 | |||
834 | */ | ||
835 | |||
836 | static int ultrastor_abort(Scsi_Cmnd *SCpnt) | ||
837 | { | ||
838 | #if ULTRASTOR_DEBUG & UD_ABORT | ||
839 | char out[108]; | ||
840 | unsigned char icm_status = 0, ogm_status = 0; | ||
841 | unsigned int icm_addr = 0, ogm_addr = 0; | ||
842 | #endif | ||
843 | unsigned int mscp_index; | ||
844 | unsigned char old_aborted; | ||
845 | unsigned long flags; | ||
846 | void (*done)(Scsi_Cmnd *); | ||
847 | struct Scsi_Host *host = SCpnt->device->host; | ||
848 | |||
849 | if(config.slot) | ||
850 | return FAILED; /* Do not attempt an abort for the 24f */ | ||
851 | |||
852 | /* Simple consistency checking */ | ||
853 | if(!SCpnt->host_scribble) | ||
854 | return FAILED; | ||
855 | |||
856 | mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp; | ||
857 | if (mscp_index >= ULTRASTOR_MAX_CMDS) | ||
858 | panic("Ux4F aborting invalid MSCP"); | ||
859 | |||
860 | #if ULTRASTOR_DEBUG & UD_ABORT | ||
861 | if (config.slot) | ||
862 | { | ||
863 | int port0 = (config.slot << 12) | 0xc80; | ||
864 | int i; | ||
865 | unsigned long flags; | ||
866 | |||
867 | spin_lock_irqsave(host->host_lock, flags); | ||
868 | strcpy(out, "OGM %d:%x ICM %d:%x ports: "); | ||
869 | for (i = 0; i < 16; i++) | ||
870 | { | ||
871 | unsigned char p = inb(port0 + i); | ||
872 | out[28 + i * 3] = "0123456789abcdef"[p >> 4]; | ||
873 | out[29 + i * 3] = "0123456789abcdef"[p & 15]; | ||
874 | out[30 + i * 3] = ' '; | ||
875 | } | ||
876 | out[28 + i * 3] = '\n'; | ||
877 | out[29 + i * 3] = 0; | ||
878 | ogm_status = inb(port0 + 22); | ||
879 | ogm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 23)); | ||
880 | icm_status = inb(port0 + 27); | ||
881 | icm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 28)); | ||
882 | spin_lock_irqsave(host->host_lock, flags); | ||
883 | } | ||
884 | |||
885 | /* First check to see if an interrupt is pending. I suspect the SiS | ||
886 | chipset loses interrupts. (I also suspect is mangles data, but | ||
887 | one bug at a time... */ | ||
888 | if (config.slot ? inb(config.icm_address - 1) == 2 : | ||
889 | (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1)) | ||
890 | { | ||
891 | printk("Ux4F: abort while completed command pending\n"); | ||
892 | |||
893 | spin_lock_irqsave(host->host_lock, flags); | ||
894 | /* FIXME: Ewww... need to think about passing host around properly */ | ||
895 | ultrastor_interrupt(0, NULL, NULL); | ||
896 | spin_unlock_irqrestore(host->host_lock, flags); | ||
897 | return SUCCESS; | ||
898 | } | ||
899 | #endif | ||
900 | |||
901 | old_aborted = xchgb(DID_ABORT, &config.aborted[mscp_index]); | ||
902 | |||
903 | /* aborted == 0xff is the signal that queuecommand has not yet sent | ||
904 | the command. It will notice the new abort flag and fail. */ | ||
905 | if (old_aborted == 0xff) | ||
906 | return SUCCESS; | ||
907 | |||
908 | /* On 24F, send an abort MSCP request. The adapter will interrupt | ||
909 | and the interrupt handler will call done. */ | ||
910 | if (config.slot && inb(config.ogm_address - 1) == 0) | ||
911 | { | ||
912 | unsigned long flags; | ||
913 | |||
914 | spin_lock_irqsave(host->host_lock, flags); | ||
915 | outl(isa_virt_to_bus(&config.mscp[mscp_index]), config.ogm_address); | ||
916 | udelay(8); | ||
917 | outb(0x80, config.ogm_address - 1); | ||
918 | outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address)); | ||
919 | #if ULTRASTOR_DEBUG & UD_ABORT | ||
920 | log_ultrastor_abort(&config, mscp_index); | ||
921 | printk(out, ogm_status, ogm_addr, icm_status, icm_addr); | ||
922 | #endif | ||
923 | spin_unlock_irqrestore(host->host_lock, flags); | ||
924 | /* FIXME: add a wait for the abort to complete */ | ||
925 | return SUCCESS; | ||
926 | } | ||
927 | |||
928 | #if ULTRASTOR_DEBUG & UD_ABORT | ||
929 | log_ultrastor_abort(&config, mscp_index); | ||
930 | #endif | ||
931 | |||
932 | /* Can't request a graceful abort. Either this is not a 24F or | ||
933 | the OGM is busy. Don't free the command -- the adapter might | ||
934 | still be using it. Setting SCint = 0 causes the interrupt | ||
935 | handler to ignore the command. */ | ||
936 | |||
937 | /* FIXME - devices that implement soft resets will still be running | ||
938 | the command after a bus reset. We would probably rather leave | ||
939 | the command in the queue. The upper level code will automatically | ||
940 | leave the command in the active state instead of requeueing it. ERY */ | ||
941 | |||
942 | #if ULTRASTOR_DEBUG & UD_ABORT | ||
943 | if (config.mscp[mscp_index].SCint != SCpnt) | ||
944 | printk("abort: command mismatch, %p != %p\n", | ||
945 | config.mscp[mscp_index].SCint, SCpnt); | ||
946 | #endif | ||
947 | if (config.mscp[mscp_index].SCint == 0) | ||
948 | return SCSI_ABORT_NOT_RUNNING; | ||
949 | |||
950 | if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort"); | ||
951 | config.mscp[mscp_index].SCint = NULL; | ||
952 | done = config.mscp[mscp_index].done; | ||
953 | config.mscp[mscp_index].done = NULL; | ||
954 | SCpnt->result = DID_ABORT << 16; | ||
955 | |||
956 | /* Take the host lock to guard against scsi layer re-entry */ | ||
957 | spin_lock_irqsave(host->host_lock, flags); | ||
958 | done(SCpnt); | ||
959 | spin_unlock_irqrestore(host->host_lock, flags); | ||
960 | |||
961 | /* Need to set a timeout here in case command never completes. */ | ||
962 | return SUCCESS; | ||
963 | } | ||
964 | |||
965 | static int ultrastor_host_reset(Scsi_Cmnd * SCpnt) | ||
966 | { | ||
967 | unsigned long flags; | ||
968 | int i; | ||
969 | struct Scsi_Host *host = SCpnt->device->host; | ||
970 | |||
971 | #if (ULTRASTOR_DEBUG & UD_RESET) | ||
972 | printk("US14F: reset: called\n"); | ||
973 | #endif | ||
974 | |||
975 | if(config.slot) | ||
976 | return FAILED; | ||
977 | |||
978 | spin_lock_irqsave(host->host_lock, flags); | ||
979 | /* Reset the adapter and SCSI bus. The SCSI bus reset can be | ||
980 | inhibited by clearing ultrastor_bus_reset before probe. */ | ||
981 | outb(0xc0, LCL_DOORBELL_INTR(config.doorbell_address)); | ||
982 | if (config.slot) | ||
983 | { | ||
984 | outb(0, config.ogm_address - 1); | ||
985 | outb(0, config.icm_address - 1); | ||
986 | } | ||
987 | |||
988 | #if ULTRASTOR_MAX_CMDS == 1 | ||
989 | if (config.mscp_busy && config.mscp->done && config.mscp->SCint) | ||
990 | { | ||
991 | config.mscp->SCint->result = DID_RESET << 16; | ||
992 | config.mscp->done(config.mscp->SCint); | ||
993 | } | ||
994 | config.mscp->SCint = 0; | ||
995 | #else | ||
996 | for (i = 0; i < ULTRASTOR_MAX_CMDS; i++) | ||
997 | { | ||
998 | if (! (config.mscp_free & (1 << i)) && | ||
999 | config.mscp[i].done && config.mscp[i].SCint) | ||
1000 | { | ||
1001 | config.mscp[i].SCint->result = DID_RESET << 16; | ||
1002 | config.mscp[i].done(config.mscp[i].SCint); | ||
1003 | config.mscp[i].done = NULL; | ||
1004 | } | ||
1005 | config.mscp[i].SCint = NULL; | ||
1006 | } | ||
1007 | #endif | ||
1008 | |||
1009 | /* FIXME - if the device implements soft resets, then the command | ||
1010 | will still be running. ERY | ||
1011 | |||
1012 | Even bigger deal with new_eh! | ||
1013 | */ | ||
1014 | |||
1015 | memset((unsigned char *)config.aborted, 0, sizeof config.aborted); | ||
1016 | #if ULTRASTOR_MAX_CMDS == 1 | ||
1017 | config.mscp_busy = 0; | ||
1018 | #else | ||
1019 | config.mscp_free = ~0; | ||
1020 | #endif | ||
1021 | |||
1022 | spin_unlock_irqrestore(host->host_lock, flags); | ||
1023 | return SCSI_RESET_SUCCESS; | ||
1024 | |||
1025 | } | ||
1026 | |||
1027 | int ultrastor_biosparam(struct scsi_device *sdev, struct block_device *bdev, | ||
1028 | sector_t capacity, int * dkinfo) | ||
1029 | { | ||
1030 | int size = capacity; | ||
1031 | unsigned int s = config.heads * config.sectors; | ||
1032 | |||
1033 | dkinfo[0] = config.heads; | ||
1034 | dkinfo[1] = config.sectors; | ||
1035 | dkinfo[2] = size / s; /* Ignore partial cylinders */ | ||
1036 | #if 0 | ||
1037 | if (dkinfo[2] > 1024) | ||
1038 | dkinfo[2] = 1024; | ||
1039 | #endif | ||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
1044 | { | ||
1045 | unsigned int status; | ||
1046 | #if ULTRASTOR_MAX_CMDS > 1 | ||
1047 | unsigned int mscp_index; | ||
1048 | #endif | ||
1049 | struct mscp *mscp; | ||
1050 | void (*done)(Scsi_Cmnd *); | ||
1051 | Scsi_Cmnd *SCtmp; | ||
1052 | |||
1053 | #if ULTRASTOR_MAX_CMDS == 1 | ||
1054 | mscp = &config.mscp[0]; | ||
1055 | #else | ||
1056 | mscp = (struct mscp *)isa_bus_to_virt(inl(config.icm_address)); | ||
1057 | mscp_index = mscp - config.mscp; | ||
1058 | if (mscp_index >= ULTRASTOR_MAX_CMDS) { | ||
1059 | printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp); | ||
1060 | /* A command has been lost. Reset and report an error | ||
1061 | for all commands. */ | ||
1062 | ultrastor_host_reset(dev_id); | ||
1063 | return; | ||
1064 | } | ||
1065 | #endif | ||
1066 | |||
1067 | /* Clean ICM slot (set ICMINT bit to 0) */ | ||
1068 | if (config.slot) { | ||
1069 | unsigned char icm_status = inb(config.icm_address - 1); | ||
1070 | #if ULTRASTOR_DEBUG & (UD_INTERRUPT|UD_ERROR|UD_ABORT) | ||
1071 | if (icm_status != 1 && icm_status != 2) | ||
1072 | printk("US24F: ICM status %x for MSCP %d (%x)\n", icm_status, | ||
1073 | mscp_index, (unsigned int) mscp); | ||
1074 | #endif | ||
1075 | /* The manual says clear interrupt then write 0 to ICM status. | ||
1076 | This seems backwards, but I'll do it anyway. --jfc */ | ||
1077 | outb(2, SYS_DOORBELL_INTR(config.doorbell_address)); | ||
1078 | outb(0, config.icm_address - 1); | ||
1079 | if (icm_status == 4) { | ||
1080 | printk("UltraStor abort command failed\n"); | ||
1081 | return; | ||
1082 | } | ||
1083 | if (icm_status == 3) { | ||
1084 | void (*done)(Scsi_Cmnd *) = mscp->done; | ||
1085 | if (done) { | ||
1086 | mscp->done = NULL; | ||
1087 | mscp->SCint->result = DID_ABORT << 16; | ||
1088 | done(mscp->SCint); | ||
1089 | } | ||
1090 | return; | ||
1091 | } | ||
1092 | } else { | ||
1093 | outb(1, SYS_DOORBELL_INTR(config.doorbell_address)); | ||
1094 | } | ||
1095 | |||
1096 | SCtmp = mscp->SCint; | ||
1097 | mscp->SCint = NULL; | ||
1098 | |||
1099 | if (SCtmp == 0) | ||
1100 | { | ||
1101 | #if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT) | ||
1102 | printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp); | ||
1103 | #endif | ||
1104 | #if ULTRASTOR_MAX_CMDS == 1 | ||
1105 | config.mscp_busy = FALSE; | ||
1106 | #else | ||
1107 | set_bit(mscp_index, &config.mscp_free); | ||
1108 | #endif | ||
1109 | config.aborted[mscp_index] = 0; | ||
1110 | return; | ||
1111 | } | ||
1112 | |||
1113 | /* Save done locally and zero before calling. This is needed as | ||
1114 | once we call done, we may get another command queued before this | ||
1115 | interrupt service routine can return. */ | ||
1116 | done = mscp->done; | ||
1117 | mscp->done = NULL; | ||
1118 | |||
1119 | /* Let the higher levels know that we're done */ | ||
1120 | switch (mscp->adapter_status) | ||
1121 | { | ||
1122 | case 0: | ||
1123 | status = DID_OK << 16; | ||
1124 | break; | ||
1125 | case 0x01: /* invalid command */ | ||
1126 | case 0x02: /* invalid parameters */ | ||
1127 | case 0x03: /* invalid data list */ | ||
1128 | default: | ||
1129 | status = DID_ERROR << 16; | ||
1130 | break; | ||
1131 | case 0x84: /* SCSI bus abort */ | ||
1132 | status = DID_ABORT << 16; | ||
1133 | break; | ||
1134 | case 0x91: | ||
1135 | status = DID_TIME_OUT << 16; | ||
1136 | break; | ||
1137 | } | ||
1138 | |||
1139 | SCtmp->result = status | mscp->target_status; | ||
1140 | |||
1141 | SCtmp->host_scribble = NULL; | ||
1142 | |||
1143 | /* Free up mscp block for next command */ | ||
1144 | #if ULTRASTOR_MAX_CMDS == 1 | ||
1145 | config.mscp_busy = FALSE; | ||
1146 | #else | ||
1147 | set_bit(mscp_index, &config.mscp_free); | ||
1148 | #endif | ||
1149 | |||
1150 | #if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT) | ||
1151 | if (config.aborted[mscp_index]) | ||
1152 | printk("Ux4 interrupt: MSCP %d (%x) aborted = %d\n", | ||
1153 | mscp_index, (unsigned int) mscp, config.aborted[mscp_index]); | ||
1154 | #endif | ||
1155 | config.aborted[mscp_index] = 0; | ||
1156 | |||
1157 | if (done) | ||
1158 | done(SCtmp); | ||
1159 | else | ||
1160 | printk("US14F: interrupt: unexpected interrupt\n"); | ||
1161 | |||
1162 | if (config.slot ? inb(config.icm_address - 1) : | ||
1163 | (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1)) | ||
1164 | #if (ULTRASTOR_DEBUG & UD_MULTI_CMD) | ||
1165 | printk("Ux4F: multiple commands completed\n"); | ||
1166 | #else | ||
1167 | ; | ||
1168 | #endif | ||
1169 | |||
1170 | #if (ULTRASTOR_DEBUG & UD_INTERRUPT) | ||
1171 | printk("USx4F: interrupt: returning\n"); | ||
1172 | #endif | ||
1173 | } | ||
1174 | |||
1175 | static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id, | ||
1176 | struct pt_regs *regs) | ||
1177 | { | ||
1178 | unsigned long flags; | ||
1179 | struct Scsi_Host *dev = dev_id; | ||
1180 | |||
1181 | spin_lock_irqsave(dev->host_lock, flags); | ||
1182 | ultrastor_interrupt(irq, dev_id, regs); | ||
1183 | spin_unlock_irqrestore(dev->host_lock, flags); | ||
1184 | return IRQ_HANDLED; | ||
1185 | } | ||
1186 | |||
1187 | MODULE_LICENSE("GPL"); | ||
1188 | |||
1189 | static Scsi_Host_Template driver_template = { | ||
1190 | .name = "UltraStor 14F/24F/34F", | ||
1191 | .detect = ultrastor_detect, | ||
1192 | .release = ultrastor_release, | ||
1193 | .info = ultrastor_info, | ||
1194 | .queuecommand = ultrastor_queuecommand, | ||
1195 | .eh_abort_handler = ultrastor_abort, | ||
1196 | .eh_host_reset_handler = ultrastor_host_reset, | ||
1197 | .bios_param = ultrastor_biosparam, | ||
1198 | .can_queue = ULTRASTOR_MAX_CMDS, | ||
1199 | .sg_tablesize = ULTRASTOR_14F_MAX_SG, | ||
1200 | .cmd_per_lun = ULTRASTOR_MAX_CMDS_PER_LUN, | ||
1201 | .unchecked_isa_dma = 1, | ||
1202 | .use_clustering = ENABLE_CLUSTERING, | ||
1203 | }; | ||
1204 | #include "scsi_module.c" | ||