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