Annotation of Gnu-Mach/linux/src/drivers/scsi/ultrastor.c, revision 1.1

1.1     ! root        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:  *         ([email protected])
        !             6:  *  scatter/gather added by Scott Taylor ([email protected])
        !             7:  *  24F and multiple command support by John F. Carr ([email protected])
        !             8:  *    John's work modified by Caleb Epstein ([email protected]) and 
        !             9:  *    Eric Youngdale ([email protected]).
        !            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 <[email protected]>
        !            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 ([email protected]) */
        !            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)
        !           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:    <[email protected]> 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,
        !           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,
        !           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)
        !           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)) {
        !           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)) {
        !           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")) {
        !           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)
        !           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)
        !           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:       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)
        !           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_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)
        !           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, unsigned int reset_flags)
        !           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)
        !          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_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, 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);
        !          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) :
        !          1148:        (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
        !          1149: #if (ULTRASTOR_DEBUG & UD_MULTI_CMD)
        !          1150:       printk("Ux4F: multiple commands completed\n");
        !          1151: #else
        !          1152:       ;
        !          1153: #endif
        !          1154: 
        !          1155: #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
        !          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;
        !          1163: 
        !          1164: #include "scsi_module.c"
        !          1165: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.