Annotation of linux/kernel/blk_drv/scsi/fdomain.c, revision 1.1.1.1

1.1       root        1: /* fdomain.c -- Future Domain TMC-1660/TMC-1680 driver
                      2:  * Created: Sun May  3 18:53:19 1992
                      3:  * Revised: Tue Jul 28 19:45:25 1992 by root
                      4:  * Author: Rickard E. Faith, [email protected]
                      5:  * Copyright 1992 Rickard E. Faith
                      6:  *
                      7:  * $Log$
                      8: 
                      9:  * This program is free software; you can redistribute it and/or modify it
                     10:  * under the terms of the GNU General Public License as published by the
                     11:  * Free Software Foundation; either version 2, or (at your option) any
                     12:  * later version.
                     13: 
                     14:  * This program is distributed in the hope that it will be useful, but
                     15:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     17:  * General Public License for more details.
                     18: 
                     19:  * WARNING: THIS IS A BETA VERSION!
                     20:  *          USE AT YOUR OWN RISK!
                     21:  *          BACKUP YOUR SYSTEM BEFORE USING!
                     22: 
                     23:  * I would like to thank Maxtor, whose *free* 206 page manual on the LXT
                     24:  * drives was very helpful: "LXT SCSI Products: Specifications and OEM
                     25:  * Technical Manual (Revision B/September 1991)"
                     26: 
                     27:  * I wish that I could thank Future Domain for the necessary documentation,
                     28:  * but I can't.  I used the $25 "TMC-1800 SCSI Chip Specification" document
                     29:  * (FDC-1800T), which documents the *chip* and not the board.  Without it,
                     30:  * I would have been totally lost, but it would have been nice to have some
                     31:  * example source.  (The DOS BIOS source cost $250 and the UN*X driver
                     32:  * source was $750 [both required a non-disclosure agreement].  Ever wonder
                     33:  * why there are no freely available Future Domain drivers?)
                     34: 
                     35:  * Thanks to Todd Carrico ([email protected]), Dan Poirier
                     36:  * ([email protected] ), Ken Corey ([email protected]), and C. de Bruin
                     37:  * ([email protected]) for alpha testing.  Also thanks to Drew
                     38:  * Eckhardt ([email protected]) for answering questions. */
                     39: 
                     40: #include <linux/config.h>
                     41: 
                     42: #ifdef CONFIG_SCSI_FUTURE_DOMAIN
                     43: 
                     44: #include <linux/sched.h>
                     45: #include <asm/io.h>
                     46: #include "fdomain.h"
                     47: #include "scsi.h"
                     48: #include "hosts.h"
                     49: #if QUEUE
                     50: #include <asm/system.h>
                     51: #include <linux/errno.h>
                     52: #endif
                     53: 
                     54: #define VERSION          "1.9" /* Change with each revision */
                     55: #define DEBUG            1     /* Enable debugging output */
                     56: #define SEND_IDENTIFY    0     /* Send IDENTIFY message -- DOESN'T WORK! */
                     57: #define USE_FIFO         1     /* Use the FIFO buffer for I/O */
                     58: #define FAST_SYNCH       1     /* Enable Fast Synchronous */
                     59: #define ALLOW_ALL_IRQ    0     /* Allow all IRQ's -- NOT RECOMMENDED */
                     60: #define NEW_IRQ          1     /* Enable new IRQ handling */
                     61: #define DECREASE_IL      1     /* Try to decrease interrupt latency */
                     62: 
                     63: #if DEBUG
                     64: #define EVERY_ACCESS     0     /* Write a line on every scsi access */
                     65: #define ERRORS_ONLY      1     /* Only write a line if there is an error */
                     66: #define DEBUG_DETECT     0     /* Debug fdomain_16x0_detect() */
                     67: #else
                     68: #define EVERY_ACCESS     0     /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
                     69: #define ERRORS_ONLY      0
                     70: #define DEBUG_DETECT     0
                     71: #endif
                     72: 
                     73: /* Errors are reported on the line, so we don't need to report them again */
                     74: #if EVERY_ACCESS
                     75: #undef ERRORS_ONLY
                     76: #define ERRORS_ONLY      0
                     77: #endif
                     78: 
                     79: static int               port_base = 0;
                     80: static void              *bios_base = NULL;
                     81: static int               interrupt_level = 0;
                     82: static volatile int      aborted = 0;
                     83: 
                     84: static int               Data_Mode_Cntl_port;
                     85: static int               FIFO_Data_Count_port;
                     86: static int               Interrupt_Cntl_port;
                     87: static int               Read_FIFO_port;
                     88: static int               Read_SCSI_Data_port;
                     89: static int               SCSI_Cntl_port;
                     90: static int               SCSI_Status_port;
                     91: static int               TMC_Cntl_port;
                     92: static int               TMC_Status_port;
                     93: static int               Write_FIFO_port;
                     94: static int               Write_SCSI_Data_port;
                     95: 
                     96: #if QUEUE
                     97: static unsigned char     current_target = 0;
                     98: static unsigned char     current_cmnd[10] = { 0, };
                     99: static void              *current_buff = NULL;
                    100: static int               current_bufflen = 0;
                    101: static void              (*current_done)(int,int) = NULL;
                    102: 
                    103: volatile static int      in_command = 0;
                    104: volatile static int      current_phase;
                    105: static int               this_host = 0;
                    106: 
                    107: enum { in_arbitration, in_selection, in_other };
                    108: 
                    109: #if NEW_IRQ
                    110: extern void              fdomain_16x0_intr( int unused );
                    111: #else
                    112: extern void              fdomain_16x0_interrupt();
                    113: #endif
                    114: 
                    115: static const char        *cmd_pt;
                    116: static const char        *the_command;
                    117: static unsigned char     *out_buf_pt;
                    118: static unsigned char     *in_buf_pt;
                    119: volatile static int      Status;
                    120: volatile static int      Message;
                    121: volatile static unsigned data_sent;
                    122: volatile static int      have_data_in;
                    123: 
                    124: volatile static int      in_interrupt_code = 0;
                    125: 
                    126: #endif
                    127: 
                    128: 
                    129: enum in_port_type { Read_SCSI_Data = 0, SCSI_Status = 1, TMC_Status = 2,
                    130:                          LSB_ID_Code = 5, MSB_ID_Code = 6, Read_Loopback = 7,
                    131:                          SCSI_Data_NoACK = 8, Option_Select = 10,
                    132:                          Read_FIFO = 12, FIFO_Data_Count = 14 };
                    133: 
                    134: enum out_port_type { Write_SCSI_Data = 0, SCSI_Cntl = 1, Interrupt_Cntl = 2,
                    135:                           Data_Mode_Cntl = 3, TMC_Cntl = 4, Write_Loopback = 7,
                    136:                           Write_FIFO = 12 };
                    137: 
                    138: static void *addresses[] = {
                    139:    (void *)0xc8000,
                    140:    (void *)0xca000,
                    141:    (void *)0xce000,
                    142:    (void *)0xde000 };
                    143: #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
                    144:                       
                    145: static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
                    146: #define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
                    147: 
                    148: static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
                    149: 
                    150: /*
                    151: 
                    152:   READ THIS BEFORE YOU ADD A SIGNATURE!
                    153: 
                    154:   READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME!
                    155: 
                    156:   READ EVERY WORD, ESPECIALLY THE WORD *NOT*
                    157: 
                    158:   This driver works *ONLY* for Future Domain cards using the
                    159:   TMC-1600 chip.  This includes models TMC-1660 and TMC-1680
                    160:   *ONLY*.
                    161: 
                    162:   The following is a BIOS signature for a TMC-950 board, which
                    163:   looks like it is a 16 bit board (based on card edge), but
                    164:   which only uses the extra lines for IRQ's (not for data):
                    165: 
                    166:   FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
                    167: 
                    168:   THIS WILL *NOT* WORK WITH THIS DRIVER!
                    169: 
                    170:   Here is another BIOS signature for yet another Future
                    171:   Domain board WHICH WILL *NOT* WORK WITH THIS DRIVER:
                    172: 
                    173:   FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
                    174: 
                    175:   Here is another BIOS signature for the TMC-88x series:
                    176: 
                    177:   FUTURE DOMAIN COPR. (C) 1986-1989 V6.0A7/28/90
                    178: 
                    179:   THIS WILL *NOT* WORK WITH THIS DRIVER, but it *WILL*
                    180:   work with the *SEAGATE* ST-01/ST-02 driver.
                    181: 
                    182:   */
                    183: 
                    184: struct signature {
                    185:    char *signature;
                    186:    int  sig_offset;
                    187:    int  sig_length;
                    188: } signatures[] = {
                    189:    { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0 7/28/89", 5, 50 },
                    190:    { "FUTURE DOMAIN CORP. (C) 1986-1990 1800", 5, 37 },
                    191:    /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGANTURE */
                    192: };
                    193: 
                    194: #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
                    195: 
                    196: 
                    197: /* These functions are based on include/asm/io.h */
                    198: 
                    199: #if 1
                    200: static unsigned short inline inw( unsigned short port )
                    201: {
                    202:    unsigned short _v;
                    203:    
                    204:    __asm__ volatile ("inw %1,%0"
                    205:                     :"=a" (_v):"d" ((unsigned short) port));
                    206:    return _v;
                    207: }
                    208: 
                    209: static void inline outw( unsigned short value, unsigned short port )
                    210: {
                    211:    __asm__ volatile ("outw %0,%1"
                    212:                     ::"a" ((unsigned short) value),
                    213:                     "d" ((unsigned short) port));
                    214: }
                    215: #else
                    216: 
                    217: #define inw( port ) \
                    218:       ({ unsigned short _v; \
                    219:               __asm__ volatile ("inw %1,%0" \
                    220:                                : "=a" (_v) : "d" ((unsigned short) port)); \
                    221:                                      _v; })
                    222: 
                    223: #define outw( value ) \
                    224:       __asm__ volatile \
                    225:       ("outw %0,%1" : : "a" ((unsigned short) value), \
                    226:        "d" ((unsigned short) port))
                    227: #endif
                    228: 
                    229: 
                    230: /* These defines are copied from kernel/blk_drv/hd.c */
                    231: 
                    232: #define insw( buf, count, port ) \
                    233:       __asm__ volatile \
                    234:       ( "cld;rep;insw"::"d" (port),"D" (buf),"c" (count):"cx","di" )
                    235: 
                    236: #define outsw( buf, count, port) \
                    237:       __asm__ volatile \
                    238:       ("cld;rep;outsw"::"d" (port),"S" (buf),"c" (count):"cx","si")
                    239: 
                    240: 
                    241: static void do_pause( unsigned amount )        /* Pause for amount*10 milliseconds */
                    242: {
                    243:    unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
                    244: 
                    245:    while (jiffies < the_time);
                    246: }
                    247: 
                    248: static void inline fdomain_make_bus_idle( void )
                    249: {
                    250:    outb( 0, SCSI_Cntl_port );
                    251:    outb( 0, Data_Mode_Cntl_port );
                    252:    outb( 1, TMC_Cntl_port );
                    253: }
                    254: 
                    255: static int fdomain_is_valid_port( int port )
                    256: {
                    257:    int options;
                    258: 
                    259: #if DEBUG_DETECT 
                    260:    printk( " (%x%x),",
                    261:          inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );
                    262: #endif
                    263: 
                    264:    /* The MCA ID is a unique id for each MCA compatible board.  We
                    265:       are using ISA boards, but Future Domain provides the MCA ID
                    266:       anyway.  We can use this ID to ensure that this is a Future
                    267:       Domain TMC-1660/TMC-1680.
                    268:     */
                    269: 
                    270:    if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */
                    271:       if (inb( port + LSB_ID_Code ) != 0x27) return 0;
                    272:       if (inb( port + MSB_ID_Code ) != 0x61) return 0;
                    273:    } else {                                /* test for 0xe960 id */
                    274:       if (inb( port + MSB_ID_Code ) != 0x60) return 0;
                    275:    }
                    276: 
                    277:    /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board.
                    278:       Now, check to be sure the bios_base matches these ports.
                    279:       If someone was unlucky enough to have purchased more than one
                    280:       Future Domain board, then they will have to modify this code, as
                    281:       we only detect one board here.  [The one with the lowest bios_base].
                    282:     */
                    283: 
                    284:    options = inb( port + Option_Select );
                    285: 
                    286: #if DEBUG_DETECT
                    287:    printk( " Options = %x,", options );
                    288: #endif
                    289: 
                    290:    if (addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
                    291:    interrupt_level = ints[ (options & 0x0e) >> 1 ];
                    292: 
                    293:    return 1;
                    294: }
                    295: 
                    296: static int fdomain_test_loopback( void )
                    297: {
                    298:    int i;
                    299:    int result;
                    300: 
                    301:    for (i = 0; i < 255; i++) {
                    302:       outb( i, port_base + Write_Loopback );
                    303:       result = inb( port_base + Read_Loopback );
                    304:       if (i != result) return 1;
                    305:    }
                    306:    return 0;
                    307: }
                    308: 
                    309: #if !NEW_IRQ
                    310: static void fdomain_enable_interrupt( void )
                    311: {
                    312:    if (!interrupt_level) return;
                    313: 
                    314: #if ALLOW_ALL_IRQ
                    315:    if (interrupt_level < 8) {
                    316:       outb( inb_p( 0x21 ) & ~(1 << interrupt_level), 0x21 );
                    317:    } else
                    318: #endif
                    319:         {
                    320:            outb( inb_p( 0xa1 ) & ~(1 << (interrupt_level - 8)), 0xa1 );
                    321:         }
                    322: }
                    323: 
                    324: static void fdomain_disable_interrupt( void )
                    325: {
                    326:    if (!interrupt_level) return;
                    327: 
                    328: #if ALLOW_ALL_IRQ
                    329:    if (interrupt_level < 8) {
                    330:       outb( inb_p( 0x21 ) | (1 << interrupt_level), 0x21 );
                    331:    } else
                    332: #endif
                    333:         {
                    334:            outb( inb_p( 0xa1 ) | (1 << (interrupt_level - 8)), 0xa1 );
                    335:         }
                    336: }
                    337: #endif
                    338: 
                    339: int fdomain_16x0_detect( int hostnum )
                    340: {
                    341:    int           i, j;
                    342:    int           flag;
                    343:    unsigned char do_inquiry[] =       { 0x12, 0, 0, 0, 255, 0 };
                    344:    unsigned char do_request_sense[] = { 0x03, 0, 0, 0, 255, 0 };
                    345:    unsigned char do_read_capacity[] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
                    346:    unsigned char buf[256];
                    347:    unsigned      retcode;
                    348: 
                    349: #if DEBUG_DETECT
                    350:    printk( "SCSI: fdomain_16x0_detect()," );
                    351: #endif
                    352: 
                    353:    for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
                    354: #if DEBUG_DETECT
                    355:       printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );
                    356: #endif
                    357:       for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
                    358:         if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),
                    359:                    signatures[j].signature, signatures[j].sig_length )) {
                    360:            bios_base = addresses[i];
                    361:         }
                    362:       }
                    363:    }
                    364: 
                    365:    if (!bios_base) {
                    366: #if DEBUG_DETECT
                    367:       printk( " FAILED: NO BIOS\n" );
                    368: #endif
                    369:       return 0;
                    370:    }
                    371: 
                    372:    /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
                    373:       Assuming the ROM is enabled (otherwise we wouldn't have been
                    374:       able to read the ROM signature :-), then the ROM set up the
                    375:       RAM area with some magic numbers, such as a list of port
                    376:       base addresses and a list of the disk "geometry" reported to
                    377:       DOS (this geometry has nothing to do with physical geometry).
                    378:     */
                    379: 
                    380:    port_base = *((char *)bios_base + 0x1fcc)
                    381:         + (*((char *)bios_base + 0x1fcd) << 8);
                    382:    
                    383: #if DEBUG_DETECT
                    384:    printk( " %x,", port_base );
                    385: #endif
                    386: 
                    387:    for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
                    388:       if (port_base == ports[i]) ++flag;
                    389:    }
                    390: 
                    391:    if (flag) flag = fdomain_is_valid_port( port_base );
                    392: 
                    393:    if (!flag) {                        /* Cannot get port base from BIOS RAM */
                    394:       
                    395:       /* This is a bad sign.  It usually means that someone patched the
                    396:         BIOS signature list (the signatures variable) to contain a BIOS
                    397:         signature for a board *OTHER THAN* the TMC-1660/TMC-1680.
                    398:        */
                    399:       
                    400: #if DEBUG_DETECT
                    401:       printk( " RAM FAILED, " );
                    402: #endif
                    403:       /* Anyway, the alternative to finding the address in the RAM is
                    404:         to just search through every possible port address for one
                    405:         that is attached to the Future Domain card.  Don't panic,
                    406:         though, about reading all these random port addresses--there
                    407:         are rumors that the Future Domain BIOS does something very
                    408:         similar.
                    409:        */
                    410: 
                    411:       for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
                    412:         port_base = ports[i];
                    413: #if DEBUG_DETECT
                    414:         printk( " %x,", port_base );
                    415: #endif
                    416:         flag = fdomain_is_valid_port( port_base );
                    417:       }
                    418:    }
                    419: 
                    420:    if (!flag) {
                    421: #if DEBUG_DETECT
                    422:       printk( " FAILED: NO PORT\n" );
                    423: #endif
                    424:       return 0;                /* Cannot find valid set of ports */
                    425:    }
                    426: 
                    427: #if DEBUG_DETECT
                    428:    printk( "\n" );
                    429:    printk( "SCSI: bios_base = %x, port_base = %x, interrupt_level = %d\n",
                    430:          (unsigned)bios_base, port_base, interrupt_level );
                    431: #endif
                    432: 
                    433:    if (interrupt_level) {
                    434:       printk( "Future Domain BIOS at %x; port base at %x; using IRQ %d\n",
                    435:             (unsigned)bios_base, port_base, interrupt_level );
                    436:    } else {
                    437:       printk( "Future Domain BIOS at %x; port base at %x; *NO* IRQ\n",
                    438:             (unsigned)bios_base, port_base );
                    439:    }
                    440:    
                    441:    Data_Mode_Cntl_port  = port_base + Data_Mode_Cntl;
                    442:    FIFO_Data_Count_port = port_base + FIFO_Data_Count;
                    443:    Interrupt_Cntl_port  = port_base + Interrupt_Cntl;
                    444:    Read_FIFO_port       = port_base + Read_FIFO;
                    445:    Read_SCSI_Data_port  = port_base + Read_SCSI_Data;
                    446:    SCSI_Cntl_port       = port_base + SCSI_Cntl;
                    447:    SCSI_Status_port     = port_base + SCSI_Status;
                    448:    TMC_Cntl_port        = port_base + TMC_Cntl;
                    449:    TMC_Status_port      = port_base + TMC_Status;
                    450:    Write_FIFO_port      = port_base + Write_FIFO;
                    451:    Write_SCSI_Data_port = port_base + Write_SCSI_Data;
                    452: 
                    453:    fdomain_16x0_reset();
                    454: 
                    455:    if (fdomain_test_loopback()) {
                    456: #if DEBUG_DETECT
                    457:       printk( "SCSI: LOOPBACK TEST FAILED, FAILING DETECT!\n" );
                    458: #endif
                    459:       return 0;
                    460:    }
                    461: 
                    462:    /* These routines are here because of the way the SCSI bus behaves
                    463:       after a reset.  This appropriate behavior was not handled correctly
                    464:       by the higher level SCSI routines when I first wrote this driver.
                    465:     */
                    466:    
                    467:    printk( "Future Domain detection routine scanning for devices:\n" );
                    468:    for (i = 0; i < 8; i++) {
                    469:       if (i == 6) continue;    /* The host adapter is at SCSI ID 6 */
                    470:       retcode = fdomain_16x0_command( i, do_request_sense, buf, 255 );
                    471:       if (!retcode) {
                    472:         retcode = fdomain_16x0_command( i, do_inquiry, buf, 255 );
                    473:         if (!retcode) {
                    474:            printk( "     SCSI ID %d: ", i );
                    475:            for (j = 8; j < 32; j++) printk( "%c", buf[j] );
                    476:            retcode = fdomain_16x0_command( i, do_read_capacity, buf, 255 );
                    477:            if (!retcode) {
                    478:               unsigned long blocks, size, capacity;
                    479:               
                    480:               blocks = (buf[0] << 24) | (buf[1] << 16)
                    481:                     | (buf[2] << 8) | buf[3];
                    482:               size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
                    483:               capacity = +(blocks * size * 10) / +(1024L * 1024L);
                    484: 
                    485:               printk( "%lu MB (%lu byte blocks)",
                    486:                      ((capacity + 5L) / 10L), size );
                    487:            }
                    488:            printk ("\n" );
                    489:         }
                    490:       }
                    491:    }
                    492: 
                    493: #if QUEUE
                    494: #if !ALLOW_ALL_IRQ
                    495:    if (interrupt_level < 8) {
                    496:       printk( "Future Domain: WILL NOT USE IRQ LESS THAN 8 FOR QUEUEING!\n" );
                    497:       scsi_hosts[hostnum].can_queue = 0;
                    498:    } else
                    499: #endif
                    500: #if NEW_IRQ
                    501:         {
                    502:            int              retcode;
                    503:            struct sigaction sa;
                    504: 
                    505:            this_host      = hostnum;
                    506: 
                    507:            sa.sa_handler  = fdomain_16x0_intr;
                    508:            sa.sa_flags    = SA_INTERRUPT;
                    509:            sa.sa_mask     = 0;
                    510:            sa.sa_restorer = NULL;
                    511: 
                    512:            retcode = irqaction( interrupt_level, &sa );
                    513: 
                    514:            if (retcode < 0) {
                    515:               if (retcode == -EINVAL) {
                    516:                  printk( "Future Domain: IRQ %d is bad!\n", interrupt_level );
                    517:                  printk( "       This shouldn't happen: REPORT TO RIK!\n" );
                    518:               } else if (retcode == -EBUSY) {
                    519:                  printk( "Future Domain: IRQ %d is already in use!\n",
                    520:                         interrupt_level );
                    521:                  printk( "       Please use another IRQ for the FD card!\n" );
                    522:               } else {
                    523:                  printk( "Future Domain: Error getting IRQ %d\n",
                    524:                         interrupt_level );
                    525:                  printk( "       This shouldn't happen: REPORT TO RIK!\n" );
                    526:               }
                    527:               printk( "       IRQs WILL NOT BE USED!\n" );
                    528:               
                    529:               scsi_hosts[this_host].can_queue = 0;
                    530:            } else {
                    531:               printk( "Future Domain: IRQ %d selected with retcode = %d\n",
                    532:                       interrupt_level, retcode );
                    533:            }
                    534:         }
                    535: #else
                    536:         {
                    537:            this_host = hostnum;
                    538:            set_intr_gate( 0x20 + interrupt_level, &fdomain_16x0_interrupt );
                    539:            fdomain_enable_interrupt();
                    540:         }
                    541: #endif
                    542: #endif
                    543: 
                    544:    return 1;
                    545: }
                    546: 
                    547: char *fdomain_16x0_info(void)
                    548: {
                    549:    static char buffer[] =
                    550:         "Future Domain TMC-1660/TMC-1680 SCSI driver version "
                    551:               VERSION
                    552:                     "\n";
                    553:    return buffer;
                    554: }
                    555: 
                    556: static int fdomain_arbitrate( void )
                    557: {
                    558:    int           status = 0;
                    559:    unsigned long timeout;
                    560: 
                    561: #if VERBOSE
                    562:    printk( "SCSI: fdomain_arbitrate()\n" );
                    563: #endif
                    564:    
                    565:    outb( 0x00, SCSI_Cntl_port );              /* Disable data drivers */
                    566:    outb( 0x40, port_base + SCSI_Data_NoACK ); /* Set our id bit */
                    567:    outb( 0x04, TMC_Cntl_port );                      /* Start arbitration */
                    568: 
                    569:    timeout = jiffies + 50;                   /* 500 mS */
                    570:    while (jiffies < timeout) {
                    571:       status = inb( TMC_Status_port );        /* Read adapter status */
                    572:       if (status & 0x02) return 0;            /* Arbitration complete */
                    573:    }
                    574: 
                    575:    /* Make bus idle */
                    576:    fdomain_make_bus_idle();
                    577: 
                    578: #if EVERY_ACCESS
                    579:    printk( "Arbitration failed, status = %x\n", status );
                    580: #endif
                    581: #if ERRORS_ONLY
                    582:    printk( "SCSI: Arbitration failed, status = %x", status );
                    583: #endif
                    584:    return 1;
                    585: }
                    586: 
                    587: static int fdomain_select( int target )
                    588: {
                    589:    int           status;
                    590:    unsigned long timeout;
                    591: 
                    592:    outb( 0x80, SCSI_Cntl_port );       /* Bus Enable */
                    593:    outb( 0x8a, SCSI_Cntl_port );       /* Bus Enable + Attention + Select */
                    594: 
                    595:    /* Send our address OR'd with target address */
                    596: #if SEND_IDENTIFY
                    597:    outb( 0x40 | (1 << target), port_base + SCSI_Data_NoACK );
                    598: #else
                    599:    outb( (1 << target), port_base + SCSI_Data_NoACK );
                    600: #endif
                    601: 
                    602:     /* Stop arbitration (also set FIFO for output and enable parity) */
                    603:    outb( 0xc8, TMC_Cntl_port ); 
                    604: 
                    605:    timeout = jiffies + 25;             /* 250mS */
                    606:    while (jiffies < timeout) {
                    607:       status = inb( SCSI_Status_port ); /* Read adapter status */
                    608:       if (status & 1) {                        /* Busy asserted */
                    609:         /* Enable SCSI Bus (on error, should make bus idle with 0) */
                    610: #if SEND_IDENTIFY
                    611:         /* Also, set ATN so that the drive will make a MESSAGE OUT phase */
                    612:         outb( 0x88, SCSI_Cntl_port );
                    613: #else
                    614:         outb( 0x80, SCSI_Cntl_port );
                    615: #endif
                    616:         return 0;
                    617:       }
                    618:    }
                    619:    /* Make bus idle */
                    620:    fdomain_make_bus_idle();
                    621: #if EVERY_ACCESS
                    622:    if (!target) printk( "Select failed\n" );
                    623: #endif
                    624: #if ERRORS_ONLY
                    625:    if (!target) printk( "SCSI: Select failed" );
                    626: #endif
                    627:    return 1;
                    628: }
                    629: 
                    630: #if QUEUE
                    631: 
                    632: #if !USE_FIFO
                    633: #pragma error QUEUE requires USE_FIFO
                    634: #endif
                    635: 
                    636: void my_done( int error )
                    637: {
                    638:    if (in_command) {
                    639:       in_command = 0;
                    640:       in_interrupt_code = 0;
                    641:       outb( 0x00, Interrupt_Cntl_port );
                    642:       fdomain_make_bus_idle();
                    643:       if (current_done) current_done( this_host, error );
                    644:       else panic( "SCSI (Future Domain): current_done() == NULL" );
                    645:    } else {
                    646:       panic( "SCSI (Future Domain): my_done() called outside of command\n" );
                    647:    }
                    648: }
                    649: 
                    650: #if NEW_IRQ
                    651: void fdomain_16x0_intr( int unused )
                    652: #else
                    653: void fdomain_16x0_intr( void )
                    654: #endif
                    655: {
                    656:    int      status;
                    657:    int      done = 0;
                    658:    unsigned data_count;
                    659: 
                    660: #if NEW_IRQ
                    661:    sti();
                    662: #endif
                    663: 
                    664:    if (in_interrupt_code)
                    665:         panic( "SCSI (Future Domain): fdomain_16x0_intr() NOT REENTRANT!\n" );
                    666:    else
                    667:         ++in_interrupt_code;
                    668:    
                    669:    outb( 0x00, Interrupt_Cntl_port );
                    670: 
                    671: #if EVERY_ACCESS
                    672:    printk( "aborted = %d, ", aborted );
                    673: #endif
                    674: 
                    675:    if (aborted) {
                    676:       /* Force retry for timeouts after selection complete */
                    677:       if (current_phase == in_other)
                    678:            my_done( DID_BUS_BUSY << 16 );
                    679:       else
                    680:            my_done( aborted << 16 );
                    681: #if NEW_IRQ && !DECREASE_IL
                    682:       cli();
                    683: #endif
                    684:       return;
                    685:    }
                    686: 
                    687:    /* We usually have one spurious interrupt after each command.  Ignore it. */
                    688:    if (!in_command) {          /* Spurious interrupt */
                    689:       in_interrupt_code = 0;
                    690: #if NEW_IRQ && !DECREASE_IL
                    691:       cli();
                    692: #endif
                    693:       return;
                    694:    }
                    695:    
                    696:    if (current_phase == in_arbitration) {
                    697:       status = inb( TMC_Status_port );        /* Read adapter status */
                    698:       if (!(status & 0x02)) {
                    699: #if EVERY_ACCESS
                    700:         printk( " AFAIL " );
                    701: #endif
                    702:         my_done( DID_TIME_OUT << 16 );
                    703: #if NEW_IRQ && !DECREASE_IL
                    704:         cli();
                    705: #endif
                    706:         return;
                    707:       }
                    708:       current_phase = in_selection;
                    709: 
                    710:       outb( 0x80, SCSI_Cntl_port );    /* Bus Enable */
                    711:       outb( 0x8a, SCSI_Cntl_port );    /* Bus Enable + Attention + Select */
                    712:       
                    713:       outb( (1 << current_target), port_base + SCSI_Data_NoACK );
                    714: 
                    715:       outb( 0x40, Interrupt_Cntl_port );
                    716:       /* Stop arbitration (also set FIFO for output and enable parity) */
                    717:       in_interrupt_code = 0;
                    718:       outb( 0xd8, TMC_Cntl_port );
                    719: #if NEW_IRQ && !DECREASE_IL
                    720:       cli();
                    721: #endif
                    722:       return;
                    723:    } else if (current_phase == in_selection) {
                    724:       status = inb( SCSI_Status_port );
                    725:       if (!(status & 0x01)) {
                    726: #if EVERY_ACCESS
                    727:         printk( " SFAIL " );
                    728: #endif
                    729:         my_done( DID_NO_CONNECT << 16 );
                    730: #if NEW_IRQ && !DECREASE_IL
                    731:         cli();
                    732: #endif
                    733:         return;
                    734:       }
                    735:       current_phase = in_other;
                    736: #if FAST_SYNCH
                    737:       outb( 0xc0, Data_Mode_Cntl_port );
                    738: #endif
                    739:       in_interrupt_code = 0;
                    740:       outb( 0x90, Interrupt_Cntl_port );
                    741:       outb( 0x80, SCSI_Cntl_port );
                    742: #if NEW_IRQ && !DECREASE_IL
                    743:       cli();
                    744: #endif
                    745:       return;
                    746:    }
                    747: 
                    748:    /* current_phase == in_other: this is the body of the routine */
                    749: 
                    750:    switch ((unsigned char)*the_command) {
                    751:    case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
                    752:    case 0x2e: case 0x3b: case 0xea: case 0x3f:
                    753:       data_count = 0x2000 - inw( FIFO_Data_Count_port );
                    754:       if (current_bufflen - data_sent < data_count)
                    755:            data_count = current_bufflen - data_sent;
                    756:       if (data_count > 0) {
                    757: /*      if (data_count > 512) data_count = 512; */
                    758: #if EVERY_ACCESS
                    759:         printk( "%d OUT, ", data_count );
                    760: #endif
                    761:         if (data_count == 1) {
                    762:            outb( *out_buf_pt++, Write_FIFO_port );
                    763:            ++data_sent;
                    764:         } else {
                    765:            data_count >>= 1;
                    766:            outsw( out_buf_pt, data_count, Write_FIFO_port );
                    767:            out_buf_pt += 2 * data_count;
                    768:            data_sent += 2 * data_count;
                    769:         }
                    770:       }
                    771:       break;
                    772:    default:
                    773:       if (!have_data_in) {
                    774:         outb( 0x98, TMC_Cntl_port );
                    775:         ++have_data_in;
                    776:       } else {
                    777:         data_count = inw( FIFO_Data_Count_port );
                    778: /*      if (data_count > 512) data_count = 512; */
                    779:         if (data_count) {
                    780: #if EVERY_ACCESS
                    781:            printk( "%d IN, ", data_count );
                    782: #endif
                    783:            if (data_count == 1) {
                    784:               *in_buf_pt++ = inb( Read_FIFO_port );
                    785:            } else {
                    786:               data_count >>= 1; /* Number of words */
                    787:               insw( in_buf_pt, data_count, Read_FIFO_port );
                    788:               in_buf_pt += 2 * data_count;
                    789:            }
                    790:         }
                    791:       }
                    792:       break;
                    793:    }
                    794: 
                    795:    status = inb( SCSI_Status_port );
                    796: 
                    797:    if (status & 0x10) {        /* REQ */
                    798:       
                    799:       switch (status & 0x0e) {
                    800:       case 0x08:               /* COMMAND OUT */
                    801:         outb( *cmd_pt++, Write_SCSI_Data_port );
                    802: #if EVERY_ACCESS
                    803:         printk( "CMD = %x,", (unsigned char)cmd_pt[-1] );
                    804: #endif
                    805:         break;
                    806:       case 0x0c:               /* STATUS IN */
                    807:         Status = inb( Read_SCSI_Data_port );
                    808: #if EVERY_ACCESS
                    809:         printk( "Status = %x, ", Status );
                    810: #endif
                    811: #if ERRORS_ONLY
                    812:         if (Status) {
                    813:            printk( "SCSI: target = %d, command = %x, Status = %x\n",
                    814:                   current_target, (unsigned char)*the_command, Status );
                    815:         }
                    816: #endif
                    817:         break;
                    818:       case 0x0a:               /* MESSAGE OUT */
                    819: #if SEND_IDENTIFY
                    820:         /* On the first request, send an Identify message */
                    821:         if (!sent_identify) {
                    822:            outb( 0x80, SCSI_Cntl_port );          /* Lower ATN */
                    823:            outb( 0x80, Write_SCSI_Data_port );    /* Identify */
                    824:            ++sent_identify;
                    825:         } else
                    826: #else
                    827:               outb( 0x07, Write_SCSI_Data_port ); /* Reject */
                    828: #endif
                    829:         break;
                    830:       case 0x0e:               /* MESSAGE IN */
                    831:         Message = inb( Read_SCSI_Data_port );
                    832: #if EVERY_ACCESS
                    833:         printk( "Message = %x, ", Message );
                    834: #endif
                    835:         if (!Message) ++done;
                    836:         break;
                    837:       }
                    838:    }
                    839: 
                    840:    if (done) {
                    841: #if EVERY_ACCESS
                    842:       printk( " ** IN DONE ** " );
                    843: #endif
                    844: 
                    845:       if (have_data_in) {
                    846:         while (data_count = inw( FIFO_Data_Count_port )) {
                    847:            if (data_count == 1) {
                    848:               *in_buf_pt++ = inb( Read_FIFO_port );
                    849:            } else {
                    850:               data_count >>= 1; /* Number of words */
                    851:               insw( in_buf_pt, data_count, Read_FIFO_port );
                    852:               in_buf_pt += 2 * data_count;
                    853:            }
                    854:         }
                    855:       }
                    856: #if EVERY_ACCESS
                    857:       printk( "AFTER DATA GET\n" );
                    858: #endif
                    859:       
                    860: #if ERRORS_ONLY
                    861:       if (*the_command == REQUEST_SENSE && !Status) {
                    862:         if ((unsigned char)(*((char *)current_buff + 2)) & 0x0f) {
                    863:            printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n",
                    864:                   (unsigned char)(*((char *)current_buff + 2)) & 0x0f,
                    865:                   (unsigned char)(*((char *)current_buff + 12)) );
                    866:         }
                    867:       }
                    868: #endif
                    869: #if EVERY_ACCESS
                    870:       printk( "BEFORE MY_DONE\n" );
                    871: #endif
                    872:       my_done( (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) );
                    873:    } else {
                    874:       in_interrupt_code = 0;
                    875:       outb( 0x90, Interrupt_Cntl_port );
                    876:    }
                    877: 
                    878: #if NEW_IRQ && !DECREASE_IL
                    879:    cli();
                    880: #endif
                    881:    return;
                    882: }
                    883: 
                    884: int fdomain_16x0_queue( unsigned char target, const void *cmnd,
                    885:                         void *buff, int bufflen, void (*done)(int,int) )
                    886: {
                    887:    if (in_command) {
                    888:       panic( "SCSI (Future Domain): fdomain_16x0_queue() NOT REENTRANT!\n" );
                    889:    }
                    890: #if EVERY_ACCESS
                    891:    printk( "queue %d %x\n", target, *(unsigned char *)cmnd );
                    892: #endif
                    893: 
                    894:    fdomain_make_bus_idle();
                    895: 
                    896:    aborted         = 0;
                    897:    current_target  = target;
                    898:    memcpy( current_cmnd, cmnd, ((*(unsigned char *)cmnd) <= 0x1f ? 6 : 10 ) );
                    899:    current_buff    = buff;
                    900:    current_bufflen = bufflen;
                    901:    current_done    = done;
                    902: 
                    903:    /* Initialize static data */
                    904:    cmd_pt          = current_cmnd;
                    905:    the_command     = current_cmnd;
                    906:    out_buf_pt      = current_buff;
                    907:    in_buf_pt       = current_buff;
                    908:    
                    909:    Status          = 0;
                    910:    Message         = 0;
                    911:    data_sent       = 0;
                    912:    have_data_in    = 0;
                    913: 
                    914:    /* Start arbitration */
                    915:    current_phase = in_arbitration;
                    916:    outb( 0x00, Interrupt_Cntl_port );
                    917:    outb( 0x00, SCSI_Cntl_port );              /* Disable data drivers */
                    918:    outb( 0x40, port_base + SCSI_Data_NoACK ); /* Set our id bit */
                    919:    ++in_command;
                    920:    outb( 0x20, Interrupt_Cntl_port );
                    921:    outb( 0x1c, TMC_Cntl_port );                      /* Start arbitration */
                    922: 
                    923:    return 0;
                    924: }
                    925: #endif
                    926: 
                    927: int fdomain_16x0_command( unsigned char target, const void *cmnd,
                    928:                         void *buff, int bufflen )
                    929: {
                    930:    const char     *cmd_pt = cmnd;
                    931:    const char     *the_command = cmnd;
                    932:    unsigned char  *out_buf_pt = buff;
                    933:    unsigned char  *in_buf_pt = buff;
                    934:    int            Status = 0;
                    935:    int            Message = 0;
                    936:    int            status;
                    937:    int            done = 0;
                    938:    unsigned long  timeout;
                    939:    unsigned       data_sent = 0;
                    940:    unsigned       data_count;
                    941: #if USE_FIFO
                    942:    int            have_data_in = 0;
                    943: #endif
                    944: #if SEND_IDENTITY
                    945:    int            sent_identify = 0;
                    946: #endif
                    947: 
                    948: #if EVERY_ACCESS
                    949:    printk( "fdomain_command(%d, %x): ", target, (unsigned char)*the_command );
                    950: #endif
                    951: 
                    952:    if (fdomain_arbitrate()) {
                    953: #if ERRORS_ONLY
                    954:       printk( ", target = %d, command = %x\n",
                    955:             target, (unsigned char)*the_command );
                    956: #endif
                    957:       return DID_TIME_OUT << 16;
                    958:    }
                    959: 
                    960:    if (fdomain_select( target )) {
                    961: #if ERRORS_ONLY
                    962:       if (!target) printk( ", target = %d, command = %x\n",
                    963:                         target, (unsigned char)*the_command );
                    964: #endif
                    965:       return DID_NO_CONNECT << 16;
                    966:    }
                    967: 
                    968:    timeout = jiffies + 500;    /* 5000 mS -- For Maxtor after a RST */
                    969:    aborted = 0;                        /* How is this supposed to get reset??? */
                    970: 
                    971: #if FAST_SYNCH
                    972:    outb( 0xc0, Data_Mode_Cntl_port );
                    973: #endif
                    974: 
                    975: #if USE_FIFO
                    976:    switch ((unsigned char)*the_command) {
                    977:    case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
                    978:    case 0x2e: case 0x3b: case 0xea: case 0x3f:
                    979:       data_count = 0x2000 - inw( FIFO_Data_Count_port );
                    980:       if (bufflen - data_sent < data_count)
                    981:            data_count = bufflen - data_sent;
                    982:       if (data_count == 1) {
                    983:         outb( *out_buf_pt++, Write_FIFO_port );
                    984:         ++data_sent;
                    985:       } else {
                    986:         data_count >>= 1;
                    987:         outsw( out_buf_pt, data_count, Write_FIFO_port );
                    988:         out_buf_pt += 2 * data_count;
                    989:         data_sent += 2 * data_count;
                    990:       }
                    991:       break;
                    992:    default:
                    993:       outb( 0x88, TMC_Cntl_port );
                    994:       ++have_data_in;
                    995:       break;
                    996:    }
                    997: #endif
                    998:    
                    999:    while (((status = inb( SCSI_Status_port )) & 1)
                   1000:          && !done && !aborted && jiffies < timeout) {
                   1001:       
                   1002:       if (status & 0x10) {     /* REQ */
                   1003: 
                   1004:         switch (status & 0x0e) {
                   1005:         case 0x00:             /* DATA OUT */
                   1006: #if USE_FIFO
                   1007:            data_count = 0x2000 - inw( FIFO_Data_Count_port );
                   1008:            if (bufflen - data_sent < data_count)
                   1009:                  data_count = bufflen - data_sent;
                   1010:            if (data_count == 1) {
                   1011:               outb( *out_buf_pt++, Write_FIFO_port );
                   1012:               ++data_sent;
                   1013:            } else {
                   1014:               data_count >>= 1;
                   1015:               outsw( out_buf_pt, data_count, Write_FIFO_port );
                   1016:               out_buf_pt += 2 * data_count;
                   1017:               data_sent += 2 * data_count;
                   1018:            }
                   1019: #else
                   1020:            outb( *out_buf_pt++, Write_SCSI_Data_port );
                   1021: #endif
                   1022:            break;
                   1023:         case 0x04:             /* DATA IN */
                   1024: #if USE_FIFO
                   1025:            if (!have_data_in) {
                   1026:               outb( 0x88, TMC_Cntl_port );
                   1027:               ++have_data_in;
                   1028:            }
                   1029:            data_count = inw( FIFO_Data_Count_port );
                   1030:            if (data_count == 1) {
                   1031:               *in_buf_pt++ = inb( Read_FIFO_port );
                   1032:            } else {
                   1033:               data_count >>= 1; /* Number of words */
                   1034:               insw( in_buf_pt, data_count, Read_FIFO_port );
                   1035:               in_buf_pt += 2 * data_count;
                   1036:            }
                   1037: #else
                   1038:            *in_buf_pt++ = inb( Read_SCSI_Data_port );
                   1039: #endif
                   1040:            break;
                   1041:         case 0x08:             /* COMMAND OUT */
                   1042:            outb( *cmd_pt++, Write_SCSI_Data_port );
                   1043: #if EVERY_ACCESS
                   1044:            printk( "%x,", (unsigned char)cmd_pt[-1] );
                   1045: #endif
                   1046:            break;
                   1047:         case 0x0c:             /* STATUS IN */
                   1048:            Status = inb( Read_SCSI_Data_port );
                   1049: #if EVERY_ACCESS
                   1050:            printk( "Status = %x, ", Status );
                   1051: #endif
                   1052: #if ERRORS_ONLY
                   1053:            if (Status) {
                   1054:               printk( "SCSI: target = %d, command = %x, Status = %x\n",
                   1055:                      target, (unsigned char)*the_command, Status );
                   1056:            }
                   1057: #endif
                   1058:            break;
                   1059:         case 0x0a:             /* MESSAGE OUT */
                   1060: #if SEND_IDENTIFY
                   1061:            /* On the first request, send an Identify message */
                   1062:            if (!sent_identify) {
                   1063:               outb( 0x80, SCSI_Cntl_port );          /* Lower ATN */
                   1064:               outb( 0x80, Write_SCSI_Data_port );    /* Identify */
                   1065:               ++sent_identify;
                   1066:            } else
                   1067: #else
                   1068:                  outb( 0x07, Write_SCSI_Data_port ); /* Reject */
                   1069: #endif
                   1070:            break;
                   1071:         case 0x0e:             /* MESSAGE IN */
                   1072:            Message = inb( Read_SCSI_Data_port );
                   1073: #if EVERY_ACCESS
                   1074:            printk( "Message = %x, ", Message );
                   1075: #endif
                   1076:            if (!Message) ++done;
                   1077:            break;
                   1078:         }
                   1079:       }
                   1080:    }
                   1081: 
                   1082:    if (jiffies >= timeout) {
                   1083: #if EVERY_ACCESS
                   1084:       printk( "Time out, status = %x\n", status );
                   1085: #endif
                   1086: #if ERRORS_ONLY
                   1087:       printk( "SCSI: Time out, status = %x (target = %d, command = %x)\n",
                   1088:             status, target, (unsigned char)*the_command );
                   1089: #endif
                   1090:       fdomain_make_bus_idle();
                   1091:       return DID_BUS_BUSY << 16;
                   1092:    }
                   1093: 
                   1094:    if (aborted) {
                   1095: #if EVERY_ACCESS
                   1096:       printk( "Aborted\n" );
                   1097: #endif
                   1098: #if ONLY_ERRORS
                   1099:       printk( "SCSI: Aborted (command = %x)\n", (unsigned char)*the_command );
                   1100: #endif
                   1101:       fdomain_16x0_reset();
                   1102:       return DID_ABORT << 16;
                   1103:    }
                   1104:    
                   1105: #if USE_FIFO
                   1106:    if (have_data_in) {
                   1107:       while (data_count = inw( FIFO_Data_Count_port )) {
                   1108:         if (data_count == 1) {
                   1109:            *in_buf_pt++ = inb( Read_FIFO_port );
                   1110:         } else {
                   1111:            data_count >>= 1; /* Number of words */
                   1112:            insw( in_buf_pt, data_count, Read_FIFO_port );
                   1113:            in_buf_pt += 2 * data_count;
                   1114:         }
                   1115:       }
                   1116:    }
                   1117: #endif
                   1118: 
                   1119:    fdomain_make_bus_idle();
                   1120: 
                   1121: #if EVERY_ACCESS
                   1122:    printk( "Retcode = %x\n",
                   1123:          (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) );
                   1124: #endif
                   1125: #if ERRORS_ONLY
                   1126:    if (*the_command == REQUEST_SENSE && !Status) {
                   1127:       if ((unsigned char)(*((char *)buff + 2)) & 0x0f) {
                   1128:         printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n",
                   1129:                (unsigned char)(*((char *)buff + 2)) & 0x0f,
                   1130:                (unsigned char)(*((char *)buff + 12)) );
                   1131:       }
                   1132:    }
                   1133: #endif
                   1134: 
                   1135:    return (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16);
                   1136: }
                   1137: 
                   1138: int fdomain_16x0_abort( int code )
                   1139: {
                   1140: 
                   1141: #if EVERY_ACCESS
                   1142:    printk( " ABORT " );
                   1143: #endif
                   1144: 
                   1145: #if QUEUE
                   1146:    cli();
                   1147:    if (!in_command) {
                   1148:       sti();
                   1149:       return 0;
                   1150:    }
                   1151: 
                   1152:    aborted = code ? code : DID_ABORT;
                   1153: 
                   1154:    sti();
                   1155:    fdomain_make_bus_idle();
                   1156: #else
                   1157:    aborted = code ? code : DID_ABORT;
                   1158: #endif
                   1159: 
                   1160:    return 0;
                   1161: }
                   1162: 
                   1163: int fdomain_16x0_reset( void )
                   1164: {
                   1165:    outb( 1, SCSI_Cntl_port );
                   1166:    do_pause( 2 );
                   1167:    outb( 0, SCSI_Cntl_port );
                   1168:    do_pause( 115 );
                   1169:    outb( 0, Data_Mode_Cntl_port );
                   1170:    outb( 0, TMC_Cntl_port );
                   1171: 
                   1172:    aborted = DID_RESET;
                   1173: 
                   1174:    return 0;
                   1175: }
                   1176: 
                   1177: #if QUEUE && !NEW_IRQ
                   1178: 
                   1179: /* This is copied from kernel/sys_calls.s
                   1180:    and from kernel/blk_drv/scsi/aha1542.c */
                   1181: 
                   1182: __asm__("
                   1183: _fdomain_16x0_interrupt:
                   1184:        cld
                   1185:        push %gs
                   1186:        push %fs
                   1187:        push %es
                   1188:        push %ds
                   1189:        pushl %eax
                   1190:        pushl %ebp
                   1191:        pushl %edi
                   1192:        pushl %esi
                   1193:        pushl %edx
                   1194:        pushl %ecx
                   1195:        pushl %ebx
                   1196:        movl $0x10,%edx
                   1197:        mov %dx,%ds
                   1198:        mov %dx,%es
                   1199:        movl $0x17,%edx
                   1200:        mov %dx,%fs
                   1201: 
                   1202:        movl $_fdomain_disable_interrupt,%edx
                   1203:        call *%edx
                   1204: 
                   1205:        movb $0x20,%al
                   1206:        outb %al,$0xA0          # EOI to interrupt controller #1
                   1207:        jmp 1f                  # give port chance to breathe
                   1208: 1:     jmp 1f
                   1209: 1:     outb %al,$0x20
                   1210: 
                   1211:        sti
                   1212:        movl $_fdomain_16x0_intr,%edx
                   1213:        call *%edx              # ``interesting'' way of handling intr.
                   1214:        cli
                   1215: 
                   1216:        movl $_fdomain_enable_interrupt,%edx
                   1217:        call *%edx
                   1218: 
                   1219:        popl %ebx
                   1220:        popl %ecx
                   1221:        popl %edx
                   1222:        popl %esi
                   1223:        popl %edi
                   1224:        popl %ebp
                   1225:        popl %eax
                   1226:        pop %ds
                   1227:        pop %es
                   1228:        pop %fs
                   1229:        pop %gs
                   1230:        iret
                   1231: ");
                   1232: #endif
                   1233: 
                   1234: #endif

unix.superglobalmegacorp.com

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