root/drivers/scsi/ultrastor.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_and_clear_bit_16
  2. xchgb
  3. log_ultrastor_abort
  4. ultrastor_14f_detect
  5. ARRAY_SIZE
  6. request_irq
  7. request_dma
  8. ultrastor_24f_detect
  9. ultrastor_detect
  10. ultrastor_info
  11. build_sg_list
  12. ultrastor_queuecommand
  13. ultrastor_abort
  14. ultrastor_reset
  15. ultrastor_biosparam
  16. ultrastor_interrupt

   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_IFDIR | S_IRUGO | S_IXUGO, 2
 153 };
 154 
 155 #define FALSE 0
 156 #define TRUE 1
 157 
 158 #ifndef ULTRASTOR_DEBUG
 159 #define ULTRASTOR_DEBUG (UD_ABORT|UD_CSIR|UD_RESET)
 160 #endif
 161 
 162 #define VERSION "1.12"
 163 
 164 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
 165 
 166 #define PACKED          __attribute__((packed))
 167 #define 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;    /* transfer data pointer */
 193   unsigned int transfer_data_length PACKED;     /* length in bytes */
 194   unsigned int command_link 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;
 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_SG]; /* use larger size for 24F */
 208 };
 209 
 210 
 211 /* Port addresses (relative to the base address) */
 212 #define U14F_PRODUCT_ID(port) ((port) + 0x4)
 213 #define CONFIG(port) ((port) + 0x6)
 214 
 215 /* Port addresses relative to the doorbell base address.  */
 216 #define LCL_DOORBELL_MASK(port) ((port) + 0x0)
 217 #define LCL_DOORBELL_INTR(port) ((port) + 0x1)
 218 #define SYS_DOORBELL_MASK(port) ((port) + 0x2)
 219 #define SYS_DOORBELL_INTR(port) ((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_CMDS == 1
 259   unsigned char mscp_busy;
 260 #else
 261   unsigned short mscp_free;
 262 #endif
 263   volatile unsigned char aborted[ULTRASTOR_MAX_CMDS];
 264   struct mscp mscp[ULTRASTOR_MAX_CMDS];
 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 *)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 inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
 298 
 299 
 300 static inline int find_and_clear_bit_16(unsigned short *field)
     /* [previous][next][first][last][top][bottom][index][help] */
 301 {
 302   int rv;
 303   unsigned long flags;
 304 
 305   save_flags(flags);
 306   cli();
 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) : "1" (*field));
 310   restore_flags(flags);
 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 inline unsigned char xchgb(unsigned char reg,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 & (UD_COMMAND | UD_ABORT)
 330 
 331 static void log_ultrastor_abort(register struct ultrastor_config *config,
     /* [previous][next][first][last][top][bottom][index][help] */
 332                                 int command)
 333 {
 334   static char fmt[80] = "abort %d (%x); MSCP free pool: %x;";
 335   register int i;
 336   int flags;
 337   save_flags(flags);
 338   cli();
 339 
 340   for (i = 0; i < ULTRASTOR_MAX_CMDS; 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_CMDS * 2] = '\n';
 349   fmt[21 + ULTRASTOR_MAX_CMDS * 2] = 0;
 350   printk(fmt, command, &config->mscp[command], config->mscp_free);
 351   restore_flags(flags);
 352 }
 353 #endif
 354 
 355 static int ultrastor_14f_detect(Scsi_Host_Template * tpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 & UD_DETECT)
 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 FALSE;
 379 
 380 #ifdef PORT_OVERRIDE
 381     if(check_region(PORT_OVERRIDE, 0xc)) {
 382       printk("Ultrastor I/O space already in use\n");
 383       return FALSE;
 384     };
 385     config.port_address = PORT_OVERRIDE;
 386 #else
 387     for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); 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 & UD_DETECT)
 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));
 397         if (in_byte != US14F_PRODUCT_ID_0) {
 398 #if (ULTRASTOR_DEBUG & UD_DETECT)
 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 FALSE;
 407 #else
 408             continue;
 409 #endif
 410         }
 411         in_byte = inb(U14F_PRODUCT_ID(config.port_address) + 1);
 412         /* Only upper nibble is significant for Product ID 1 */
 413         if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
 414 #if (ULTRASTOR_DEBUG & UD_DETECT)
 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 FALSE;
 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)) {
     /* [previous][next][first][last][top][bottom][index][help] */
 432 # if (ULTRASTOR_DEBUG & UD_DETECT)
 433         printk("US14F: detect: no port address found!\n");
 434 # endif
 435         return FALSE;
 436     }
 437 #endif
 438 
 439 #if (ULTRASTOR_DEBUG & UD_DETECT)
 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));
 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));
 455     *(char *)&config_2 = inb(CONFIG(config.port_address + 1));
 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 == U34F)
 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 & UD_DETECT)
 473         printk("US14F: detect: not detected.\n");
 474 #endif
 475         return FALSE;
 476     }
 477 
 478     /* Final consistency check, verify previous info. */
 479     if (config.subversion != U34F)
 480         if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
 481 #if (ULTRASTOR_DEBUG & UD_DETECT)
 482             printk("US14F: detect: consistency check failed\n");
 483 #endif
 484             return FALSE;
 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 & UD_DETECT)
 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 != U34F);
 505 
 506 #if ULTRASTOR_MAX_CMDS > 1
 507     config.mscp_free = ~0;
 508 #endif
 509 
 510     if (request_irq(config.interrupt, ultrastor_interrupt, 0, "Ultrastor", NULL)) {
     /* [previous][next][first][last][top][bottom][index][help] */
 511         printk("Unable to allocate IRQ%u for UltraStor controller.\n",
 512                config.interrupt);
 513         return FALSE;
 514     }
 515     if (config.dma_channel && request_dma(config.dma_channel,"Ultrastor")) {
     /* [previous][next][first][last][top][bottom][index][help] */
 516         printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
 517                config.dma_channel);
 518         free_irq(config.interrupt, NULL);
 519         return FALSE;
 520     }
 521     tpnt->sg_tablesize = ULTRASTOR_14F_MAX_SG;
 522     printk("UltraStor driver version" VERSION ".  Using %d SG lists.\n",
 523            ULTRASTOR_14F_MAX_SG);
 524 
 525     return TRUE;
 526 }
 527 
 528 static int ultrastor_24f_detect(Scsi_Host_Template * tpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 529 {
 530   register 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       if (request_irq(config.interrupt, ultrastor_interrupt, 0, "Ultrastor", NULL))
 581         {
 582           printk("Unable to allocate IRQ%u for UltraStor controller.\n",
 583                  config.interrupt);
 584           return FALSE;
 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);
 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 & UD_DETECT)
 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_SG;
 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_CMDS > 1
 615       config.mscp_free = ~0;
 616 #endif
 617       /* Mark ICM and OGM free */
 618       outb(0, addr + 0x16);
 619       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));
 624       outb(0x02, SYS_DOORBELL_MASK(addr+12));
 625       printk("UltraStor driver version " VERSION ".  Using %d SG lists.\n",
 626              tpnt->sg_tablesize);
 627       return TRUE;
 628     }
 629   return FALSE;
 630 }
 631 
 632 int ultrastor_detect(Scsi_Host_Template * tpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 639 {
 640     static char buf[64];
 641 
 642     if (config.slot)
 643       sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u",
 644               config.slot, config.interrupt);
 645     else if (config.subversion)
 646       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       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 inline void build_sg_list(register struct mscp *mscp, Scsi_Cmnd *SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 *))
     /* [previous][next][first][last][top][bottom][index][help] */
 678 {
 679     register struct mscp *my_mscp;
 680 #if ULTRASTOR_MAX_CMDS > 1
 681     int mscp_index;
 682 #endif
 683     unsigned int status;
 684     int flags;
 685 
 686     /* Next test is for debugging; "can't happen" */
 687     if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 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_ABORT << 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_SCSI | (DTD_SCSI << 3);
 703 #else
 704     my_mscp->opcode = OP_SCSI;
 705     my_mscp->xdir = DTD_SCSI;
 706     my_mscp->dcn = FALSE;
 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_TAPE;
 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 = TRUE;
 722         build_sg_list(my_mscp, SCpnt);
 723     } else {
 724         /* Unset scatter/gather flag in SCSI command packet */
 725         my_mscp->sg = FALSE;
 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);
 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) != 0 &&
 747                config.aborted[mscp_index] == 0xff) barrier();
 748 
 749     /* else??? */
 750 
 751     while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & 
 752             (config.slot ? 2 : 1)) 
 753            && config.aborted[mscp_index] == 0xff) barrier();
 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);
 759     cli();
 760 
 761     if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) &
 762         (config.slot ? 2 : 1))
 763       {
 764       restore_flags(flags);
 765       goto retry;
 766       }
 767 
 768     status = xchgb(0, &config.aborted[mscp_index]);
 769     if (status != 0xff) {
 770         restore_flags(flags);
 771 
 772 #if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
 773         printk("USx4F: queuecommand: aborted\n");
 774 #if ULTRASTOR_MAX_CMDS > 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_CMDS > 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);
 795 
 796     /* Issue OGM interrupt */
 797     if (config.slot) {
 798         /* Write OGM command register on 24F */
 799         outb(1, config.ogm_address - 1);
 800         outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
 801     } else {
 802         outb(0x1, LCL_DOORBELL_INTR(config.doorbell_address));
 803     }
 804 
 805     restore_flags(flags);
 806 
 807 #if (ULTRASTOR_DEBUG & UD_COMMAND)
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 830 {
 831 #if ULTRASTOR_DEBUG & UD_ABORT
 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_SNOOZE;  /* Do not attempt an abort for the 24f */
 842 
 843     /* Simple consistency checking */
 844     if(!SCpnt->host_scribble)
 845       return SCSI_ABORT_NOT_RUNNING;
 846 
 847     mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp;
 848     if (mscp_index >= ULTRASTOR_MAX_CMDS)
 849         panic("Ux4F aborting invalid MSCP");
 850 
 851 #if ULTRASTOR_DEBUG & UD_ABORT
 852     if (config.slot)
 853       {
 854         int port0 = (config.slot << 12) | 0xc80;
 855         int i;
 856         int flags;
 857         save_flags(flags);
 858         cli();
 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);
 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);
 870         ogm_addr = inl(port0 + 23);
 871         icm_status = inb(port0 + 27);
 872         icm_addr = inl(port0 + 28);
 873         restore_flags(flags);
 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) == 2 :
 880         (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
 881       {
 882         int flags;
 883         save_flags(flags);
 884         printk("Ux4F: abort while completed command pending\n");
 885         restore_flags(flags);
 886         cli();
 887         ultrastor_interrupt(0, NULL, NULL);
 888         restore_flags(flags);
 889         return SCSI_ABORT_SUCCESS;  /* FIXME - is this correct? -ERY */
 890       }
 891 #endif
 892 
 893     old_aborted = xchgb(DID_ABORT, &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_SUCCESS;
 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) == 0)
 903       {
 904         int flags;
 905 
 906         save_flags(flags);
 907         cli();
 908         outl((int)&config.mscp[mscp_index], config.ogm_address);
 909         inb(0xc80);     /* delay */
 910         outb(0x80, config.ogm_address - 1);
 911         outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
 912 #if ULTRASTOR_DEBUG & UD_ABORT
 913         log_ultrastor_abort(&config, mscp_index);
 914         printk(out, ogm_status, ogm_addr, icm_status, icm_addr);
 915 #endif
 916         restore_flags(flags);
 917         return SCSI_ABORT_PENDING;
 918       }
 919 
 920 #if ULTRASTOR_DEBUG & UD_ABORT
 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 & UD_ABORT
 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_RUNNING;
 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_ABORT << 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_SUCCESS;
 952 }
 953 
 954 int ultrastor_reset(Scsi_Cmnd * SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 955 {
 956     int flags;
 957     register int i;
 958 #if (ULTRASTOR_DEBUG & UD_RESET)
 959     printk("US14F: reset: called\n");
 960 #endif
 961 
 962     if(config.slot)
 963       return SCSI_RESET_PUNT;  /* Do not attempt a reset for the 24f */
 964 
 965     save_flags(flags);
 966     cli();
 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));
 971     if (config.slot)
 972       {
 973         outb(0, config.ogm_address - 1);
 974         outb(0, config.icm_address - 1);
 975       }
 976 
 977 #if ULTRASTOR_MAX_CMDS == 1
 978     if (config.mscp_busy && config.mscp->done && config.mscp->SCint)
 979       {
 980         config.mscp->SCint->result = DID_RESET << 16;
 981         config.mscp->done(config.mscp->SCint);
 982       }
 983     config.mscp->SCint = 0;
 984 #else
 985     for (i = 0; i < ULTRASTOR_MAX_CMDS; 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_RESET << 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);
1002 #if ULTRASTOR_MAX_CMDS == 1
1003     config.mscp_busy = 0;
1004 #else
1005     config.mscp_free = ~0;
1006 #endif
1007 
1008     restore_flags(flags);
1009     return SCSI_RESET_SUCCESS;
1010 
1011 }
1012 
1013 int ultrastor_biosparam(Disk * disk, kdev_t dev, int * dkinfo)
     /* [previous][next][first][last][top][bottom][index][help] */
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)
     /* [previous][next][first][last][top][bottom][index][help] */
1029 {
1030     unsigned int status;
1031 #if ULTRASTOR_MAX_CMDS > 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_CMDS == 1
1039     mscp = &config.mscp[0];
1040 #else
1041     mscp = (struct mscp *)inl(config.icm_address);
1042     mscp_index = mscp - config.mscp;
1043     if (mscp_index >= ULTRASTOR_MAX_CMDS) {
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);
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);
1055 #if ULTRASTOR_DEBUG & (UD_INTERRUPT|UD_ERROR|UD_ABORT)
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));
1063         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_ABORT << 16;
1073                 done(mscp->SCint);
1074             }
1075             return;
1076         }
1077     } else {
1078         outb(1, SYS_DOORBELL_INTR(config.doorbell_address));
1079     }
1080 
1081     SCtmp = mscp->SCint;
1082     mscp->SCint = NULL;
1083 
1084     if (SCtmp == 0)
1085       {
1086 #if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
1087         printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp);
1088 #endif  
1089 #if ULTRASTOR_MAX_CMDS == 1
1090         config.mscp_busy = FALSE;
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_OK << 16;
1109         break;
1110       case 0x01:        /* invalid command */
1111       case 0x02:        /* invalid parameters */
1112       case 0x03:        /* invalid data list */
1113       default:
1114         status = DID_ERROR << 16;
1115         break;
1116       case 0x84:        /* SCSI bus abort */
1117         status = DID_ABORT << 16;
1118         break;
1119       case 0x91:
1120         status = DID_TIME_OUT << 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_CMDS == 1
1130     config.mscp_busy = FALSE;
1131 #else
1132     set_bit(mscp_index, &config.mscp_free);
1133 #endif
1134 
1135 #if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
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) : (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
1148       printk("Ux4F: multiple commands completed\n");
1149 
1150 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
1151     printk("USx4F: interrupt: returning\n");
1152 #endif
1153 }
1154 
1155 #ifdef MODULE
1156 /* Eventually this will go into an include file, but this will be later */
1157 Scsi_Host_Template driver_template = ULTRASTOR_14F;
1158 
1159 #include "scsi_module.c"
1160 #endif

/* [previous][next][first][last][top][bottom][index][help] */