| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* mca_53c9x.c: Driver for the SCSI adapter found on NCR 35xx | 
|  | 2 | *  (and maybe some other) Microchannel machines | 
|  | 3 | * | 
|  | 4 | * Code taken mostly from Cyberstorm SCSI drivers | 
|  | 5 | *   Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk) | 
|  | 6 | * | 
|  | 7 | * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org) | 
|  | 8 | * | 
|  | 9 | * The CyberStorm SCSI driver (and this driver) is based on David S. Miller's | 
|  | 10 | *   ESP driver  * for the Sparc computers. | 
|  | 11 | * | 
|  | 12 | * Special thanks to Ken Stewart at Symbios (LSI) for helping with info on | 
|  | 13 | *  the 86C01.  I was on the brink of going ga-ga... | 
|  | 14 | * | 
|  | 15 | * Also thanks to Jesper Skov for helping me with info on how the Amiga | 
|  | 16 | *  does things... | 
|  | 17 | */ | 
|  | 18 |  | 
|  | 19 | /* | 
|  | 20 | * This is currently only set up to use one 53c9x card at a time; it could be | 
|  | 21 | *  changed fairly easily to detect/use more than one, but I'm not too sure how | 
|  | 22 | *  many cards that use the 53c9x on MCA systems there are (if, in fact, there | 
|  | 23 | *  are cards that use them, other than the one built into some NCR systems)... | 
|  | 24 | *  If anyone requests this, I'll throw it in, otherwise it's not worth the | 
|  | 25 | *  effort. | 
|  | 26 | */ | 
|  | 27 |  | 
|  | 28 | /* | 
|  | 29 | * Info on the 86C01 MCA interface chip at the bottom, if you care enough to | 
|  | 30 | *  look. | 
|  | 31 | */ | 
|  | 32 |  | 
|  | 33 | #include <linux/delay.h> | 
|  | 34 | #include <linux/interrupt.h> | 
|  | 35 | #include <linux/kernel.h> | 
|  | 36 | #include <linux/mca.h> | 
|  | 37 | #include <linux/types.h> | 
|  | 38 | #include <linux/string.h> | 
|  | 39 | #include <linux/slab.h> | 
|  | 40 | #include <linux/blkdev.h> | 
|  | 41 | #include <linux/proc_fs.h> | 
|  | 42 | #include <linux/stat.h> | 
|  | 43 | #include <linux/mca-legacy.h> | 
|  | 44 |  | 
|  | 45 | #include "scsi.h" | 
|  | 46 | #include <scsi/scsi_host.h> | 
|  | 47 | #include "NCR53C9x.h" | 
|  | 48 |  | 
|  | 49 | #include <asm/dma.h> | 
|  | 50 | #include <asm/irq.h> | 
|  | 51 | #include <asm/mca_dma.h> | 
|  | 52 | #include <asm/pgtable.h> | 
|  | 53 |  | 
|  | 54 | /* | 
|  | 55 | * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk | 
|  | 56 | *  activity LED on and off | 
|  | 57 | */ | 
|  | 58 |  | 
|  | 59 | #define PS2_SYS_CTR	0x92 | 
|  | 60 |  | 
|  | 61 | /* Ports the ncr's 53c94 can be put at; indexed by pos register value */ | 
|  | 62 |  | 
|  | 63 | #define MCA_53C9X_IO_PORTS {                             \ | 
|  | 64 | 0x0000, 0x0240, 0x0340, 0x0400, \ | 
|  | 65 | 0x0420, 0x3240, 0x8240, 0xA240, \ | 
|  | 66 | } | 
|  | 67 |  | 
|  | 68 | /* | 
|  | 69 | * Supposedly there were some cards put together with the 'c9x and 86c01.  If | 
|  | 70 | *   they have different ID's from the ones on the 3500 series machines, | 
|  | 71 | *   you can add them here and hopefully things will work out. | 
|  | 72 | */ | 
|  | 73 |  | 
|  | 74 | #define MCA_53C9X_IDS {          \ | 
|  | 75 | 0x7F4C, \ | 
|  | 76 | 0x0000, \ | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | static int  dma_bytes_sent(struct NCR_ESP *, int); | 
|  | 80 | static int  dma_can_transfer(struct NCR_ESP *, Scsi_Cmnd *); | 
|  | 81 | static void dma_dump_state(struct NCR_ESP *); | 
|  | 82 | static void dma_init_read(struct NCR_ESP *, __u32, int); | 
|  | 83 | static void dma_init_write(struct NCR_ESP *, __u32, int); | 
|  | 84 | static void dma_ints_off(struct NCR_ESP *); | 
|  | 85 | static void dma_ints_on(struct NCR_ESP *); | 
|  | 86 | static int  dma_irq_p(struct NCR_ESP *); | 
|  | 87 | static int  dma_ports_p(struct NCR_ESP *); | 
|  | 88 | static void dma_setup(struct NCR_ESP *, __u32, int, int); | 
|  | 89 | static void dma_led_on(struct NCR_ESP *); | 
|  | 90 | static void dma_led_off(struct NCR_ESP *); | 
|  | 91 |  | 
|  | 92 | /* This is where all commands are put before they are trasfered to the | 
|  | 93 | *  53c9x via PIO. | 
|  | 94 | */ | 
|  | 95 |  | 
|  | 96 | static volatile unsigned char cmd_buffer[16]; | 
|  | 97 |  | 
|  | 98 | /* | 
|  | 99 | * We keep the structure that is used to access the registers on the 53c9x | 
|  | 100 | *  here. | 
|  | 101 | */ | 
|  | 102 |  | 
|  | 103 | static struct ESP_regs eregs; | 
|  | 104 |  | 
|  | 105 | /***************************************************************** Detection */ | 
| Christoph Hellwig | d0be4a7d | 2005-10-31 18:31:40 +0100 | [diff] [blame] | 106 | static int mca_esp_detect(struct scsi_host_template *tpnt) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 107 | { | 
|  | 108 | struct NCR_ESP *esp; | 
|  | 109 | static int io_port_by_pos[] = MCA_53C9X_IO_PORTS; | 
|  | 110 | int mca_53c9x_ids[] = MCA_53C9X_IDS; | 
|  | 111 | int *id_to_check = mca_53c9x_ids; | 
|  | 112 | int slot; | 
|  | 113 | int pos[3]; | 
|  | 114 | unsigned int tmp_io_addr; | 
|  | 115 | unsigned char tmp_byte; | 
|  | 116 |  | 
|  | 117 |  | 
|  | 118 | if (!MCA_bus) | 
|  | 119 | return 0; | 
|  | 120 |  | 
|  | 121 | while (*id_to_check) { | 
|  | 122 | if ((slot = mca_find_adapter(*id_to_check, 0)) != | 
|  | 123 | MCA_NOTFOUND) | 
|  | 124 | { | 
| Maciej W. Rozycki | 4df4db5 | 2007-02-05 16:28:29 -0800 | [diff] [blame] | 125 | esp = esp_allocate(tpnt, NULL, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 126 |  | 
|  | 127 | pos[0] = mca_read_stored_pos(slot, 2); | 
|  | 128 | pos[1] = mca_read_stored_pos(slot, 3); | 
|  | 129 | pos[2] = mca_read_stored_pos(slot, 4); | 
|  | 130 |  | 
|  | 131 | esp->eregs = &eregs; | 
|  | 132 |  | 
|  | 133 | /* | 
|  | 134 | * IO port base is given in the first (non-ID) pos | 
|  | 135 | *  register, like so: | 
|  | 136 | * | 
|  | 137 | *  Bits 3  2  1       IO base | 
|  | 138 | * ---------------------------- | 
|  | 139 | *       0  0  0       <disabled> | 
|  | 140 | *       0  0  1       0x0240 | 
|  | 141 | *       0  1  0       0x0340 | 
|  | 142 | *       0  1  1       0x0400 | 
|  | 143 | *       1  0  0       0x0420 | 
|  | 144 | *       1  0  1       0x3240 | 
|  | 145 | *       1  1  0       0x8240 | 
|  | 146 | *       1  1  1       0xA240 | 
|  | 147 | */ | 
|  | 148 |  | 
|  | 149 | tmp_io_addr = | 
|  | 150 | io_port_by_pos[(pos[0] & 0x0E) >> 1]; | 
|  | 151 |  | 
|  | 152 | esp->eregs->io_addr = tmp_io_addr + 0x10; | 
|  | 153 |  | 
|  | 154 | if (esp->eregs->io_addr == 0x0000) { | 
|  | 155 | printk("Adapter is disabled.\n"); | 
|  | 156 | break; | 
|  | 157 | } | 
|  | 158 |  | 
|  | 159 | /* | 
|  | 160 | * IRQ is specified in bits 4 and 5: | 
|  | 161 | * | 
|  | 162 | *  Bits  4  5        IRQ | 
|  | 163 | * ----------------------- | 
|  | 164 | *        0  0         3 | 
|  | 165 | *        0  1         5 | 
|  | 166 | *        1  0         7 | 
|  | 167 | *        1  1         9 | 
|  | 168 | */ | 
|  | 169 |  | 
|  | 170 | esp->irq = ((pos[0] & 0x30) >> 3) + 3; | 
|  | 171 |  | 
|  | 172 | /* | 
|  | 173 | * DMA channel is in the low 3 bits of the second | 
|  | 174 | *  POS register | 
|  | 175 | */ | 
|  | 176 |  | 
|  | 177 | esp->dma = pos[1] & 7; | 
|  | 178 | esp->slot = slot; | 
|  | 179 |  | 
|  | 180 | if (request_irq(esp->irq, esp_intr, 0, | 
|  | 181 | "NCR 53c9x SCSI", esp->ehost)) | 
|  | 182 | { | 
|  | 183 | printk("Unable to request IRQ %d.\n", esp->irq); | 
|  | 184 | esp_deallocate(esp); | 
|  | 185 | scsi_unregister(esp->ehost); | 
|  | 186 | return 0; | 
|  | 187 | } | 
|  | 188 |  | 
|  | 189 | if (request_dma(esp->dma, "NCR 53c9x SCSI")) { | 
|  | 190 | printk("Unable to request DMA channel %d.\n", | 
|  | 191 | esp->dma); | 
|  | 192 | free_irq(esp->irq, esp_intr); | 
|  | 193 | esp_deallocate(esp); | 
|  | 194 | scsi_unregister(esp->ehost); | 
|  | 195 | return 0; | 
|  | 196 | } | 
|  | 197 |  | 
|  | 198 | request_region(tmp_io_addr, 32, "NCR 53c9x SCSI"); | 
|  | 199 |  | 
|  | 200 | /* | 
|  | 201 | * 86C01 handles DMA, IO mode, from address | 
|  | 202 | *  (base + 0x0a) | 
|  | 203 | */ | 
|  | 204 |  | 
|  | 205 | mca_disable_dma(esp->dma); | 
|  | 206 | mca_set_dma_io(esp->dma, tmp_io_addr + 0x0a); | 
|  | 207 | mca_enable_dma(esp->dma); | 
|  | 208 |  | 
|  | 209 | /* Tell the 86C01 to give us interrupts */ | 
|  | 210 |  | 
|  | 211 | tmp_byte = inb(tmp_io_addr + 0x02) | 0x40; | 
|  | 212 | outb(tmp_byte, tmp_io_addr + 0x02); | 
|  | 213 |  | 
|  | 214 | /* | 
|  | 215 | * Scsi ID -- general purpose register, hi | 
|  | 216 | *  2 bits; add 4 to this number to get the | 
|  | 217 | *  ID | 
|  | 218 | */ | 
|  | 219 |  | 
|  | 220 | esp->scsi_id = ((pos[2] & 0xC0) >> 6) + 4; | 
|  | 221 |  | 
|  | 222 | /* Do command transfer with programmed I/O */ | 
|  | 223 |  | 
|  | 224 | esp->do_pio_cmds = 1; | 
|  | 225 |  | 
|  | 226 | /* Required functions */ | 
|  | 227 |  | 
|  | 228 | esp->dma_bytes_sent = &dma_bytes_sent; | 
|  | 229 | esp->dma_can_transfer = &dma_can_transfer; | 
|  | 230 | esp->dma_dump_state = &dma_dump_state; | 
|  | 231 | esp->dma_init_read = &dma_init_read; | 
|  | 232 | esp->dma_init_write = &dma_init_write; | 
|  | 233 | esp->dma_ints_off = &dma_ints_off; | 
|  | 234 | esp->dma_ints_on = &dma_ints_on; | 
|  | 235 | esp->dma_irq_p = &dma_irq_p; | 
|  | 236 | esp->dma_ports_p = &dma_ports_p; | 
|  | 237 | esp->dma_setup = &dma_setup; | 
|  | 238 |  | 
|  | 239 | /* Optional functions */ | 
|  | 240 |  | 
|  | 241 | esp->dma_barrier = NULL; | 
|  | 242 | esp->dma_drain = NULL; | 
|  | 243 | esp->dma_invalidate = NULL; | 
|  | 244 | esp->dma_irq_entry = NULL; | 
|  | 245 | esp->dma_irq_exit = NULL; | 
|  | 246 | esp->dma_led_on = dma_led_on; | 
|  | 247 | esp->dma_led_off = dma_led_off; | 
|  | 248 | esp->dma_poll = NULL; | 
|  | 249 | esp->dma_reset = NULL; | 
|  | 250 |  | 
|  | 251 | /* Set the command buffer */ | 
|  | 252 |  | 
|  | 253 | esp->esp_command = (volatile unsigned char*) | 
|  | 254 | cmd_buffer; | 
|  | 255 | esp->esp_command_dvma = isa_virt_to_bus(cmd_buffer); | 
|  | 256 |  | 
|  | 257 | /* SCSI chip speed */ | 
|  | 258 |  | 
|  | 259 | esp->cfreq = 25000000; | 
|  | 260 |  | 
|  | 261 | /* Differential SCSI? I think not. */ | 
|  | 262 |  | 
|  | 263 | esp->diff = 0; | 
|  | 264 |  | 
|  | 265 | esp_initialize(esp); | 
|  | 266 |  | 
|  | 267 | printk(" Adapter found in slot %2d: io port 0x%x " | 
|  | 268 | "irq %d dma channel %d\n", slot + 1, tmp_io_addr, | 
|  | 269 | esp->irq, esp->dma); | 
|  | 270 |  | 
|  | 271 | mca_set_adapter_name(slot, "NCR 53C9X SCSI Adapter"); | 
|  | 272 | mca_mark_as_used(slot); | 
|  | 273 |  | 
|  | 274 | break; | 
|  | 275 | } | 
|  | 276 |  | 
|  | 277 | id_to_check++; | 
|  | 278 | } | 
|  | 279 |  | 
|  | 280 | return esps_in_use; | 
|  | 281 | } | 
|  | 282 |  | 
|  | 283 |  | 
|  | 284 | /******************************************************************* Release */ | 
|  | 285 |  | 
|  | 286 | static int mca_esp_release(struct Scsi_Host *host) | 
|  | 287 | { | 
|  | 288 | struct NCR_ESP *esp = (struct NCR_ESP *)host->hostdata; | 
|  | 289 | unsigned char tmp_byte; | 
|  | 290 |  | 
|  | 291 | esp_deallocate(esp); | 
|  | 292 | /* | 
|  | 293 | * Tell the 86C01 to stop sending interrupts | 
|  | 294 | */ | 
|  | 295 |  | 
|  | 296 | tmp_byte = inb(esp->eregs->io_addr - 0x0E); | 
|  | 297 | tmp_byte &= ~0x40; | 
|  | 298 | outb(tmp_byte, esp->eregs->io_addr - 0x0E); | 
|  | 299 |  | 
|  | 300 | free_irq(esp->irq, esp_intr); | 
|  | 301 | free_dma(esp->dma); | 
|  | 302 |  | 
|  | 303 | mca_mark_as_unused(esp->slot); | 
|  | 304 |  | 
|  | 305 | return 0; | 
|  | 306 | } | 
|  | 307 |  | 
|  | 308 | /************************************************************* DMA Functions */ | 
|  | 309 | static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) | 
|  | 310 | { | 
|  | 311 | /* Ask the 53c9x.  It knows. */ | 
|  | 312 |  | 
|  | 313 | return fifo_count; | 
|  | 314 | } | 
|  | 315 |  | 
|  | 316 | static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp) | 
|  | 317 | { | 
|  | 318 | /* | 
|  | 319 | * The MCA dma channels can only do up to 128K bytes at a time. | 
|  | 320 | *  (16 bit mode) | 
|  | 321 | */ | 
|  | 322 |  | 
|  | 323 | unsigned long sz = sp->SCp.this_residual; | 
|  | 324 | if(sz > 0x20000) | 
|  | 325 | sz = 0x20000; | 
|  | 326 | return sz; | 
|  | 327 | } | 
|  | 328 |  | 
|  | 329 | static void dma_dump_state(struct NCR_ESP *esp) | 
|  | 330 | { | 
|  | 331 | /* | 
|  | 332 | * Doesn't quite match up to the other drivers, but we do what we | 
|  | 333 | *  can. | 
|  | 334 | */ | 
|  | 335 |  | 
|  | 336 | ESPLOG(("esp%d: dma channel <%d>\n", esp->esp_id, esp->dma)); | 
|  | 337 | ESPLOG(("bytes left to dma: %d\n", mca_get_dma_residue(esp->dma))); | 
|  | 338 | } | 
|  | 339 |  | 
|  | 340 | static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length) | 
|  | 341 | { | 
|  | 342 | unsigned long flags; | 
|  | 343 |  | 
|  | 344 |  | 
|  | 345 | save_flags(flags); | 
|  | 346 | cli(); | 
|  | 347 |  | 
|  | 348 | mca_disable_dma(esp->dma); | 
|  | 349 | mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_16 | | 
|  | 350 | MCA_DMA_MODE_IO); | 
|  | 351 | mca_set_dma_addr(esp->dma, addr); | 
|  | 352 | mca_set_dma_count(esp->dma, length / 2); /* !!! */ | 
|  | 353 | mca_enable_dma(esp->dma); | 
|  | 354 |  | 
|  | 355 | restore_flags(flags); | 
|  | 356 | } | 
|  | 357 |  | 
|  | 358 | static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length) | 
|  | 359 | { | 
|  | 360 | unsigned long flags; | 
|  | 361 |  | 
|  | 362 |  | 
|  | 363 | save_flags(flags); | 
|  | 364 | cli(); | 
|  | 365 |  | 
|  | 366 | mca_disable_dma(esp->dma); | 
|  | 367 | mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_WRITE | | 
|  | 368 | MCA_DMA_MODE_16 | MCA_DMA_MODE_IO); | 
|  | 369 | mca_set_dma_addr(esp->dma, addr); | 
|  | 370 | mca_set_dma_count(esp->dma, length / 2); /* !!! */ | 
|  | 371 | mca_enable_dma(esp->dma); | 
|  | 372 |  | 
|  | 373 | restore_flags(flags); | 
|  | 374 | } | 
|  | 375 |  | 
|  | 376 | static void dma_ints_off(struct NCR_ESP *esp) | 
|  | 377 | { | 
|  | 378 | /* | 
|  | 379 | * Tell the 'C01 to shut up.  All interrupts are routed through it. | 
|  | 380 | */ | 
|  | 381 |  | 
|  | 382 | outb(inb(esp->eregs->io_addr - 0x0E) & ~0x40, | 
|  | 383 | esp->eregs->io_addr - 0x0E); | 
|  | 384 | } | 
|  | 385 |  | 
|  | 386 | static void dma_ints_on(struct NCR_ESP *esp) | 
|  | 387 | { | 
|  | 388 | /* | 
|  | 389 | * Ok.  You can speak again. | 
|  | 390 | */ | 
|  | 391 |  | 
|  | 392 | outb(inb(esp->eregs->io_addr - 0x0E) | 0x40, | 
|  | 393 | esp->eregs->io_addr - 0x0E); | 
|  | 394 | } | 
|  | 395 |  | 
|  | 396 | static int dma_irq_p(struct NCR_ESP *esp) | 
|  | 397 | { | 
|  | 398 | /* | 
|  | 399 | * DaveM says that this should return a "yes" if there is an interrupt | 
|  | 400 | *  or a DMA error occurred.  I copied the Amiga driver's semantics, | 
|  | 401 | *  though, because it seems to work and we can't really tell if | 
|  | 402 | *  a DMA error happened.  This gives the "yes" if the scsi chip | 
|  | 403 | *  is sending an interrupt and no DMA activity is taking place | 
|  | 404 | */ | 
|  | 405 |  | 
|  | 406 | return (!(inb(esp->eregs->io_addr - 0x04) & 1) && | 
|  | 407 | !(inb(esp->eregs->io_addr - 0x04) & 2) ); | 
|  | 408 | } | 
|  | 409 |  | 
|  | 410 | static int dma_ports_p(struct NCR_ESP *esp) | 
|  | 411 | { | 
|  | 412 | /* | 
|  | 413 | * Check to see if interrupts are enabled on the 'C01 (in case abort | 
|  | 414 | *  is entered multiple times, so we only do the abort once) | 
|  | 415 | */ | 
|  | 416 |  | 
|  | 417 | return (inb(esp->eregs->io_addr - 0x0E) & 0x40) ? 1:0; | 
|  | 418 | } | 
|  | 419 |  | 
|  | 420 | static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) | 
|  | 421 | { | 
|  | 422 | if(write){ | 
|  | 423 | dma_init_write(esp, addr, count); | 
|  | 424 | } else { | 
|  | 425 | dma_init_read(esp, addr, count); | 
|  | 426 | } | 
|  | 427 | } | 
|  | 428 |  | 
|  | 429 | /* | 
|  | 430 | * These will not play nicely with other disk controllers that try to use the | 
|  | 431 | *  disk active LED... but what can you do?  Don't answer that. | 
|  | 432 | * | 
|  | 433 | * Stolen shamelessly from ibmmca.c -- IBM Microchannel SCSI adapter driver | 
|  | 434 | * | 
|  | 435 | */ | 
|  | 436 |  | 
|  | 437 | static void dma_led_on(struct NCR_ESP *esp) | 
|  | 438 | { | 
|  | 439 | outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); | 
|  | 440 | } | 
|  | 441 |  | 
|  | 442 | static void dma_led_off(struct NCR_ESP *esp) | 
|  | 443 | { | 
|  | 444 | outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); | 
|  | 445 | } | 
|  | 446 |  | 
| Christoph Hellwig | d0be4a7d | 2005-10-31 18:31:40 +0100 | [diff] [blame] | 447 | static struct scsi_host_template driver_template = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 448 | .proc_name		= "mca_53c9x", | 
|  | 449 | .name			= "NCR 53c9x SCSI", | 
|  | 450 | .detect			= mca_esp_detect, | 
|  | 451 | .slave_alloc		= esp_slave_alloc, | 
|  | 452 | .slave_destroy		= esp_slave_destroy, | 
|  | 453 | .release		= mca_esp_release, | 
|  | 454 | .queuecommand		= esp_queue, | 
|  | 455 | .eh_abort_handler	= esp_abort, | 
|  | 456 | .eh_bus_reset_handler	= esp_reset, | 
|  | 457 | .can_queue		= 7, | 
|  | 458 | .sg_tablesize		= SG_ALL, | 
|  | 459 | .cmd_per_lun		= 1, | 
|  | 460 | .unchecked_isa_dma	= 1, | 
|  | 461 | .use_clustering		= DISABLE_CLUSTERING | 
|  | 462 | }; | 
|  | 463 |  | 
|  | 464 |  | 
|  | 465 | #include "scsi_module.c" | 
|  | 466 |  | 
|  | 467 | /* | 
|  | 468 | * OK, here's the goods I promised.  The NCR 86C01 is an MCA interface chip | 
|  | 469 | *  that handles enabling/diabling IRQ, dma interfacing, IO port selection | 
|  | 470 | *  and other fun stuff.  It takes up 16 addresses, and the chip it is | 
|  | 471 | *  connnected to gets the following 16.  Registers are as follows: | 
|  | 472 | * | 
|  | 473 | * Offsets 0-1 : Card ID | 
|  | 474 | * | 
|  | 475 | * Offset    2 : Mode enable register -- | 
|  | 476 | *                Bit    7 : Data Word width (1 = 16, 0 = 8) | 
|  | 477 | *		  Bit    6 : IRQ enable (1 = enabled) | 
|  | 478 | *                Bits 5,4 : IRQ select | 
|  | 479 | *                              0  0 : IRQ 3 | 
|  | 480 | *			        0  1 : IRQ 5 | 
|  | 481 | * 				1  0 : IRQ 7 | 
|  | 482 | *  				1  1 : IRQ 9 | 
|  | 483 | *                Bits 3-1 : Base Address | 
|  | 484 | *                           0  0  0 : <disabled> | 
|  | 485 | * 			     0  0  1 : 0x0240 | 
|  | 486 | *    			     0  1  0 : 0x0340 | 
|  | 487 | *     			     0  1  1 : 0x0400 | 
|  | 488 | * 			     1  0  0 : 0x0420 | 
|  | 489 | * 			     1  0  1 : 0x3240 | 
|  | 490 | * 			     1  1  0 : 0x8240 | 
|  | 491 | * 			     1  1  1 : 0xA240 | 
|  | 492 | *		  Bit    0 : Card enable (1 = enabled) | 
|  | 493 | * | 
|  | 494 | * Offset    3 : DMA control register -- | 
|  | 495 | *                Bit    7 : DMA enable (1 = enabled) | 
|  | 496 | *                Bits 6,5 : Preemt Count Select (transfers to complete after | 
|  | 497 | *                            'C01 has been preempted on MCA bus) | 
|  | 498 | *                              0  0 : 0 | 
|  | 499 | *                              0  1 : 1 | 
|  | 500 | *                              1  0 : 3 | 
|  | 501 | *                              1  1 : 7 | 
|  | 502 | *  (all these wacky numbers; I'm sure there's a reason somewhere) | 
|  | 503 | *                Bit    4 : Fairness enable (1 = fair bus priority) | 
|  | 504 | *                Bits 3-0 : Arbitration level (0-15 consecutive) | 
|  | 505 | * | 
|  | 506 | * Offset    4 : General purpose register | 
|  | 507 | *                Bits 7-3 : User definable (here, 7,6 are SCSI ID) | 
|  | 508 | *                Bits 2-0 : reserved | 
|  | 509 | * | 
|  | 510 | * Offset   10 : DMA decode register (used for IO based DMA; also can do | 
|  | 511 | *                PIO through this port) | 
|  | 512 | * | 
|  | 513 | * Offset   12 : Status | 
|  | 514 | *                Bits 7-2 : reserved | 
|  | 515 | *                Bit    1 : DMA pending (1 = pending) | 
|  | 516 | *                Bit    0 : IRQ pending (0 = pending) | 
|  | 517 | * | 
|  | 518 | * Exciting, huh? | 
|  | 519 | * | 
|  | 520 | */ |