Annotation of linux/kernel/blk_drv/scsi/fdomain.c, revision 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.