root/kernel/blk_drv/scsi/fdomain.c

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

DEFINITIONS

This source file includes following definitions.
  1. outw
  2. print_banner
  3. do_pause
  4. fdomain_make_bus_idle
  5. fdomain_is_valid_port
  6. fdomain_test_loopback
  7. fdomain_16x0_detect
  8. fdomain_16x0_info
  9. fdomain_arbitrate
  10. fdomain_select
  11. my_done
  12. fdomain_16x0_intr
  13. fdomain_16x0_queue
  14. fdomain_16x0_command
  15. fdomain_16x0_abort
  16. fdomain_16x0_reset
  17. fdomain_16x0_biosparam

   1 /* fdomain.c -- Future Domain TMC-1660/TMC-1680 driver
   2  * Created: Sun May  3 18:53:19 1992 by faith
   3  * Revised: Sat May 15 15:29:19 1993 by faith@cs.unc.edu
   4  * Author: Rickard E. Faith, faith@cs.unc.edu
   5  * Copyright 1992, 1993 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  **************************************************************************
  20 
  21 
  22  DESCRIPTION:
  23 
  24  This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
  25  and TMC-1650/1670 SCSI host adapters.  The older boards are based on the
  26  TMC-1800 chip, and the driver was originally written for a TMC-1680 with
  27  this chip.  More recently, boards are being produced with the TMC-18C50
  28  chip.  This driver may not work with the more recent boards.
  29 
  30 
  31  REFERENCES USED:
  32 
  33  "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation,
  34  1990.
  35 
  36  "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain
  37  Corporation, January 1992.
  38 
  39  "LXT SCSI Products: Specifications and OEM Technical Manual (Revision
  40  B/September 1991)", Maxtor Corporation, 1991.
  41 
  42  "7213S product Manual (Revision P3)", Maxtor Corporation, 1992.
  43 
  44  "Draft Proposed American National Standard: Small Computer System
  45  Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109,
  46  revision 10h, October 17, 1991)
  47 
  48  Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric
  49  Youngdale (eric@tantalus.nrl.navy.mil), 1992.
  50 
  51 
  52  NOTES ON REFERENCES:
  53 
  54  The Maxtor manuals were free.  Maxtor telephone technical support is
  55  great!
  56 
  57  The Future Domain manuals were $25 and $35.  They document the chip, not
  58  the TMC-16x0 boards, so some information I had to guess at.  In 1992,
  59  Future Domain sells DOS BIOS source for $250 and the UN*X driver source
  60  was $750, but these require a non-disclosure agreement, so even if I could
  61  afford them, they would *not* have been useful for writing this publically
  62  distributable driver.  Future Domain technical support has provided some
  63  information on the phone and have sent a few useful FAXs.
  64 
  65 
  66  ALPHA TESTERS:
  67 
  68  There are many other alpha testers that come and go as the driver
  69  develops.  The people listed here were most helpful in times of greatest
  70  need.  However, all of the alpha testers deserve much thanks.
  71 
  72  Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken
  73  Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@dutiba.tudelft.nl),
  74  Sakari Aaltonen (sakaria@vipunen.hit.fi), John Rice
  75  (rice@xanth.cs.odu.edu), and Brad Yearwood (brad@optilink.com).
  76 
  77 
  78  NOTES ON USER DEFINABLE OPTIONS:
  79 
  80  DEBUG: This turns on the printing of various debug informaiton.
  81 
  82  ENABLE_PARITY: This turns on SCSI parity checking.  With the current
  83  driver, all attached devices must support SCSI parity.  If none of your
  84  devices support parity, then you can probably get the driver to work by
  85  turning this option off.  I have no way of testing this, however.
  86 
  87  QUEUE: Enable "command queueing."  This is supported by the higher level
  88  SCSI code, and allows the kernel to continue to schedule tasks while the
  89  SCSI request is pending.  If this option is turned off, then everything
  90  will "freeze" during SCSI requests, and system performance will become
  91  unbearable.  Later, this will allow multiple outstanding SCSI requests.  I
  92  have received reports that if this option is turned off, the driver will
  93  no longer function correctly.  I have not had time to track down this bug,
  94  since I hope to make the driver work for everyone with QUEUE on.
  95 
  96  FIFO_COUNT: The host adapter has an 8K cache.  When this many 512 byte
  97  blocks are filled by the SCSI device, an interrupt will be raised.
  98  Therefore, this could be as low as 0, or as high as 16.  Note, however,
  99  that values which are too high or too low seem to prevent any interrupts
 100  from occuring, and thereby lock up the machine.  I have found that 2 is a
 101  good number, but throughput may be increased by changing this value to
 102  values which are close to 2.  Please let me know if you try any different
 103  values.
 104 
 105  DO_DETECT: This activates some old scan code which was needed before the
 106  high level drivers got fixed.  If you are having toruble with the driver,
 107  turning this on should not hurt, and might help.  Please let me know if
 108  this is the case, since this code will be removed from future drivers.
 109 
 110  RESELECTION: DO *NOT* USE THIS OPTION!  This turns on SCSI device
 111  disconnect and reselection, which does not work at this time.  When I get
 112  this working, it will support multiple outstanding SCSI commands.
 113 
 114  **************************************************************************/
 115 
 116 #include <linux/sched.h>
 117 #include <asm/io.h>
 118 #include "../blk.h"
 119 #include "scsi.h"
 120 #include "hosts.h"
 121 #include "fdomain.h"
 122 #include <asm/system.h>
 123 #include <linux/errno.h>
 124 
 125 #define VERSION          "3.6"  /* Change with each revision */
 126 
 127 /* START OF USER DEFINABLE OPTIONS */
 128 
 129 #define DEBUG            1      /* Enable debugging output */
 130 #define ENABLE_PARITY    1      /* Enable SCSI Parity */
 131 #define QUEUE            1      /* Enable command queueing */
 132 #define FIFO_COUNT       2      /* Number of 512 byte blocks before INTR */
 133 #define DO_DETECT        0      /* Do device detection here (see scsi.c) */
 134 #define RESELECTION      0      /* Support RESELECTION PHASE (NOT stable) */
 135 
 136 /* END OF USER DEFINABLE OPTIONS */
 137 
 138 #if DEBUG
 139 #define EVERY_ACCESS     0      /* Write a line on every scsi access */
 140 #define ERRORS_ONLY      1      /* Only write a line if there is an error */
 141 #define DEBUG_DETECT     0      /* Debug fdomain_16x0_detect() */
 142 #define DEBUG_MESSAGES   0      /* Debug MESSAGE IN PHASE */
 143 #define DEBUG_ABORT      1      /* Debug abort() routine */
 144 #define DEBUG_RACE       1      /* Debug interrupt-driven race condition */
 145 #else
 146 #define EVERY_ACCESS     0      /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
 147 #define ERRORS_ONLY      0
 148 #define DEBUG_DETECT     0
 149 #define DEBUG_MESSAGES   0
 150 #define DEBUG_ABORT      0
 151 #endif
 152 
 153 /* Errors are reported on the line, so we don't need to report them again */
 154 #if EVERY_ACCESS
 155 #undef ERRORS_ONLY
 156 #define ERRORS_ONLY      0
 157 #endif
 158 
 159 #if ENABLE_PARITY
 160 #define PARITY_MASK      0x08
 161 #else
 162 #define PARITY_MASK      0x00
 163 #endif
 164 
 165 enum chip_type {
 166    unknown          = 0x00,
 167    tmc1800          = 0x01,
 168    tmc18c50         = 0x02,
 169 };
 170 
 171 enum {
 172    non_queueing     = 0x01,
 173    in_arbitration   = 0x02,
 174    in_selection     = 0x04,
 175    in_other         = 0x08,
 176    disconnect       = 0x10,
 177    aborted          = 0x20,
 178    sent_ident       = 0x40,
 179 };
 180 
 181 enum in_port_type {
 182    Read_SCSI_Data   =  0,
 183    SCSI_Status      =  1,
 184    TMC_Status       =  2,
 185    FIFO_Status      =  3,       /* tmc18c50 only */
 186    Interrupt_Cond    =  4,      /* tmc18c50 only */
 187    LSB_ID_Code      =  5,
 188    MSB_ID_Code      =  6,
 189    Read_Loopback    =  7,
 190    SCSI_Data_NoACK  =  8,
 191    Interrupt_Mask   =  9,
 192    Option_Select    = 10,
 193    Configuration    = 11,       /* tmc18c50 only */
 194    Read_FIFO        = 12,
 195    FIFO_Data_Count  = 14
 196 };
 197 
 198 enum out_port_type {
 199    Write_SCSI_Data  =  0,
 200    SCSI_Cntl        =  1,
 201    Interrupt_Cntl   =  2,
 202    Data_Mode_Cntl   =  3,
 203    TMC_Cntl         =  4,
 204    Memory_Cntl      =  5,       /* tmc18c50 only */
 205    Write_Loopback   =  7,
 206    Write_FIFO       = 12
 207 };
 208 
 209 static int               port_base         = 0;
 210 static void              *bios_base        = NULL;
 211 static int               bios_major        = 0;
 212 static int               bios_minor        = 0;
 213 static int               interrupt_level   = 0;
 214 static int               this_host         = 0;
 215 static int               can_queue         = QUEUE;
 216 static volatile int      in_command        = 0;
 217 static Scsi_Cmnd         *current_SC       = NULL;
 218 static enum chip_type    chip              = unknown;
 219 #if DEBUG_RACE
 220 static volatile int      in_interrupt_flag = 0;
 221 #endif
 222 
 223 
 224 static int               Data_Mode_Cntl_port;
 225 static int               FIFO_Data_Count_port;
 226 static int               Interrupt_Cntl_port;
 227 static int               Interrupt_Mask_port;
 228 static int               Read_FIFO_port;
 229 static int               Read_SCSI_Data_port;
 230 static int               SCSI_Cntl_port;
 231 static int               SCSI_Data_NoACK_port;
 232 static int               SCSI_Status_port;
 233 static int               TMC_Cntl_port;
 234 static int               TMC_Status_port;
 235 static int               Write_FIFO_port;
 236 static int               Write_SCSI_Data_port;
 237 
 238 extern void              fdomain_16x0_intr( int unused );
 239 
 240 static void *addresses[] = {
 241    (void *)0xc8000,
 242    (void *)0xca000,
 243    (void *)0xce000,
 244    (void *)0xde000 };
 245 #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
 246                        
 247 static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
 248 #define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
 249 
 250 static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
 251 
 252 /*
 253 
 254   READ THIS BEFORE YOU ADD A SIGNATURE!
 255 
 256   READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME!
 257 
 258   READ EVERY WORD, ESPECIALLY THE WORD *NOT*
 259 
 260   This driver works *ONLY* for Future Domain cards using the TMC-1800 chip.
 261   This includes models TMC-1660, 1670, and 1680 *ONLY*.
 262 
 263   The following BIOS signatures have been tried with this driver.  These
 264   signatures are for boards which do *NOT* work with this driver (but the
 265   first one should work with the Seagate driver):
 266 
 267       FUTURE DOMAIN COPR. (C) 1986-1989 V6.0A7/28/90
 268       FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
 269       FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
 270 
 271   */
 272 
 273 struct signature {
 274    char *signature;
 275    int  sig_offset;
 276    int  sig_length;
 277    int  major_bios_version;
 278    int  minor_bios_version;
 279 } signatures[] = {
 280    /*          1         2         3         4         5         6 */
 281    /* 123456789012345678901234567890123456789012345678901234567890 */
 282    { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 2, 0 },
 283    { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92",       5, 44, 3, 0 },
 284    { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93",       5, 44, 3, 2 },
 285    /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGANTURE */
 286 };
 287 
 288 #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
 289 
 290 
 291 /* These functions are based on include/asm/io.h */
 292 
 293 inline static unsigned short inw( unsigned short port )
 294 {
 295    unsigned short _v;
 296    
 297    __asm__ volatile ( "inw %1,%0"
 298                       :"=a" (_v):"d" ((unsigned short) port) );
 299    return _v;
 300 }
 301 
 302 inline static void outw( unsigned short value, unsigned short port )
     /* [previous][next][first][last][top][bottom][index][help] */
 303 {
 304    __asm__ volatile ( "outw %0,%1"
 305                       ::"a" ((unsigned short) value),
 306                       "d" ((unsigned short) port) );
 307 }
 308 
 309 
 310 /* These defines are copied from kernel/blk_drv/hd.c */
 311 
 312 #define insw( buf, count, port ) \
 313    __asm__ volatile \
 314       ("cld;rep;insw"::"d" (port),"D" (buf),"c" (count):"cx","di" )
 315 
 316 #define outsw( buf, count, port ) \
 317     __asm__ volatile \
 318        ("cld;rep;outsw"::"d" (port),"S" (buf),"c" (count):"cx","si")
 319 
 320 
 321 static void print_banner( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 322 {
 323    printk( "%s", fdomain_16x0_info() );
 324    printk( "Future Domain: BIOS version %d.%d, %s\n",
 325            bios_major, bios_minor,
 326            chip == tmc1800 ? "TMC-1800"
 327            : (chip == tmc18c50 ? "TMC-18C50" : "Unknown") );
 328    
 329    if (interrupt_level) {
 330       printk( "Future Domain: BIOS at %x; port base at %x; using IRQ %d\n",
 331               (unsigned)bios_base, port_base, interrupt_level );
 332    } else {
 333       printk( "Future Domain: BIOS at %x; port base at %x; *NO* IRQ\n",
 334               (unsigned)bios_base, port_base );
 335    }
 336 }
 337 
 338 static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
     /* [previous][next][first][last][top][bottom][index][help] */
 339 {
 340    unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
 341 
 342    while (jiffies < the_time);
 343 }
 344 
 345 inline static void fdomain_make_bus_idle( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 346 {
 347    outb( 0, SCSI_Cntl_port );
 348    outb( 0, Data_Mode_Cntl_port );
 349    outb( 1 | PARITY_MASK, TMC_Cntl_port );
 350 }
 351 
 352 static int fdomain_is_valid_port( int port )
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354    int options;
 355 
 356 #if DEBUG_DETECT 
 357    printk( " (%x%x),",
 358            inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );
 359 #endif
 360 
 361    /* The MCA ID is a unique id for each MCA compatible board.  We
 362       are using ISA boards, but Future Domain provides the MCA ID
 363       anyway.  We can use this ID to ensure that this is a Future
 364       Domain TMC-1660/TMC-1680.
 365     */
 366 
 367    if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */
 368       if (inb( port + LSB_ID_Code ) != 0x27) return 0;
 369       if (inb( port + MSB_ID_Code ) != 0x61) return 0;
 370       chip = tmc1800;
 371    } else {                                 /* test for 0xe960 id */
 372       if (inb( port + MSB_ID_Code ) != 0x60) return 0;
 373       chip = tmc18c50;
 374    }
 375    
 376    /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board.
 377       Now, check to be sure the bios_base matches these ports.
 378       If someone was unlucky enough to have purchased more than one
 379       Future Domain board, then they will have to modify this code, as
 380       we only detect one board here.  [The one with the lowest bios_base.]
 381     */
 382 
 383    options = inb( port + Option_Select );
 384 
 385 #if DEBUG_DETECT
 386    printk( " Options = %x,", options );
 387 #endif
 388 
 389    if (addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
 390    interrupt_level = ints[ (options & 0x0e) >> 1 ];
 391 
 392    return 1;
 393 }
 394 
 395 static int fdomain_test_loopback( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 396 {
 397    int i;
 398    int result;
 399 
 400    for (i = 0; i < 255; i++) {
 401       outb( i, port_base + Write_Loopback );
 402       result = inb( port_base + Read_Loopback );
 403       if (i != result) return 1;
 404    }
 405    return 0;
 406 }
 407 
 408 int fdomain_16x0_detect( int hostnum )
     /* [previous][next][first][last][top][bottom][index][help] */
 409 {
 410    int              i, j;
 411    int              flag;
 412    struct sigaction sa;
 413    int              retcode;
 414 #if DO_DETECT
 415    const int        buflen = 255;
 416    Scsi_Cmnd        SCinit;
 417    unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };
 418    unsigned char    do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 };
 419    unsigned char    do_read_capacity[] = { READ_CAPACITY,
 420                                            0, 0, 0, 0, 0, 0, 0, 0, 0 };
 421    unsigned char    buf[buflen];
 422 #endif
 423 
 424 #if DEBUG_DETECT
 425    printk( "SCSI: fdomain_16x0_detect()," );
 426 #endif
 427 
 428    for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
 429 #if DEBUG_DETECT
 430       printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );
 431 #endif
 432       for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
 433          if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),
 434                       signatures[j].signature, signatures[j].sig_length )) {
 435             bios_major = signatures[j].major_bios_version;
 436             bios_minor = signatures[j].minor_bios_version;
 437             bios_base = addresses[i];
 438          }
 439       }
 440    }
 441 
 442    if (!bios_base) {
 443 #if DEBUG_DETECT
 444       printk( " FAILED: NO BIOS\n" );
 445 #endif
 446       return 0;
 447    }
 448 
 449    /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
 450       Assuming the ROM is enabled (otherwise we wouldn't have been
 451       able to read the ROM signature :-), then the ROM sets up the
 452       RAM area with some magic numbers, such as a list of port
 453       base addresses and a list of the disk "geometry" reported to
 454       DOS (this geometry has nothing to do with physical geometry).
 455     */
 456 
 457    port_base = *((char *)bios_base + 0x1fcc)
 458          + (*((char *)bios_base + 0x1fcd) << 8);
 459    
 460 #if DEBUG_DETECT
 461    printk( " %x,", port_base );
 462 #endif
 463 
 464    for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
 465       if (port_base == ports[i]) ++flag;
 466    }
 467 
 468    if (flag)
 469          flag = fdomain_is_valid_port( port_base );
 470 
 471    if (!flag) {                 /* Cannot get port base from BIOS RAM */
 472       
 473       /* This is a bad sign.  It usually means that someone patched the
 474          BIOS signature list (the signatures variable) to contain a BIOS
 475          signature for a board *OTHER THAN* the TMC-1660/TMC-1680.
 476        */
 477       
 478 #if DEBUG_DETECT
 479       printk( " RAM FAILED, " );
 480 #endif
 481 
 482       /* Anyway, the alternative to finding the address in the RAM is
 483          to just search through every possible port address for one
 484          that is attached to the Future Domain card.  Don't panic,
 485          though, about reading all these random port addresses--there
 486          are rumors that the Future Domain BIOS does something very
 487          similar.
 488        */
 489 
 490       for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
 491          port_base = ports[i];
 492 #if DEBUG_DETECT
 493          printk( " %x,", port_base );
 494 #endif
 495          flag = fdomain_is_valid_port( port_base );
 496       }
 497    }
 498 
 499    if (!flag) {
 500 #if DEBUG_DETECT
 501       printk( " FAILED: NO PORT\n" );
 502 #endif
 503       return 0;         /* Cannot find valid set of ports */
 504    }
 505 
 506    print_banner();
 507    if (chip == tmc18c50)
 508          printk( "Future Domain WARNING: This driver may not work with the"
 509                  " TMC-18C50 chip!\n"
 510                  "                       Send mail to faith@cs.unc.edu\n" );
 511 
 512    Data_Mode_Cntl_port  = port_base + Data_Mode_Cntl;
 513    FIFO_Data_Count_port = port_base + FIFO_Data_Count;
 514    Interrupt_Cntl_port  = port_base + Interrupt_Cntl;
 515    Interrupt_Mask_port  = port_base + Interrupt_Mask;
 516    Read_FIFO_port       = port_base + Read_FIFO;
 517    Read_SCSI_Data_port  = port_base + Read_SCSI_Data;
 518    SCSI_Cntl_port       = port_base + SCSI_Cntl;
 519    SCSI_Data_NoACK_port = port_base + SCSI_Data_NoACK;
 520    SCSI_Status_port     = port_base + SCSI_Status;
 521    TMC_Cntl_port        = port_base + TMC_Cntl;
 522    TMC_Status_port      = port_base + TMC_Status;
 523    Write_FIFO_port      = port_base + Write_FIFO;
 524    Write_SCSI_Data_port = port_base + Write_SCSI_Data;
 525 
 526    fdomain_16x0_reset();
 527 
 528    if (fdomain_test_loopback()) {
 529 #if DEBUG_DETECT
 530       printk( "SCSI: LOOPBACK TEST FAILED, FAILING DETECT!\n" );
 531 #endif
 532       return 0;
 533    }
 534 
 535 #if DO_DETECT
 536 
 537    /* These routines are here because of the way the SCSI bus behaves after
 538       a reset.  This appropriate behavior was not handled correctly by the
 539       higher level SCSI routines when I first wrote this driver.  Now,
 540       however, correct scan routines are part of scsi.c and these routines
 541       are no longer needed.  However, this code is still good for
 542       debugging.
 543     */
 544 
 545    SCinit.request_buffer  = SCinit.buffer = buf;
 546    SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1;
 547    SCinit.use_sg          = 0;
 548    SCinit.lun             = 0;
 549 
 550    printk( "Future Domain detection routine scanning for devices:\n" );
 551    for (i = 0; i < 8; i++) {
 552       SCinit.target = i;
 553       if (i == 6) continue;     /* The host adapter is at SCSI ID 6 */
 554       memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));
 555       retcode = fdomain_16x0_command(&SCinit);
 556       if (!retcode) {
 557          memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry));
 558          retcode = fdomain_16x0_command(&SCinit);
 559          if (!retcode) {
 560             printk( "     SCSI ID %d: ", i );
 561             for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++)
 562                   printk( "%c", buf[j] >= 20 ? buf[j] : ' ' );
 563             memcpy(SCinit.cmnd, do_read_capacity, sizeof(do_read_capacity));
 564             retcode = fdomain_16x0_command(&SCinit);
 565             if (!retcode) {
 566                unsigned long blocks, size, capacity;
 567                
 568                blocks = (buf[0] << 24) | (buf[1] << 16)
 569                      | (buf[2] << 8) | buf[3];
 570                size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
 571                capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L;
 572                
 573                printk( "%lu MB (%lu byte blocks)",
 574                        ((capacity + 5L) / 10L), size );
 575             } else {
 576                memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));
 577                retcode = fdomain_16x0_command(&SCinit);
 578             }
 579             printk ("\n" );
 580          } else {
 581             memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));
 582             retcode = fdomain_16x0_command(&SCinit);
 583          }
 584       }
 585    }
 586 #endif
 587 
 588    this_host = hostnum;
 589    
 590    if (!QUEUE || !interrupt_level) {
 591       printk( "Future Domain: *NO* interrupt level selected!\n" );
 592       printk( "               COMMAND QUEUEING DISABLED!\n" );
 593       can_queue = scsi_hosts[this_host].can_queue = 0;
 594       scsi_hosts[this_host].sg_tablesize = SG_NONE;
 595    } else {
 596       /* Register the IRQ with the kernel */
 597 
 598       sa.sa_handler  = fdomain_16x0_intr;
 599       sa.sa_flags    = SA_INTERRUPT;
 600       sa.sa_mask     = 0;
 601       sa.sa_restorer = NULL;
 602       
 603       retcode = irqaction( interrupt_level, &sa );
 604 
 605       if (retcode < 0) {
 606          if (retcode == -EINVAL) {
 607             printk( "Future Domain: IRQ %d is bad!\n", interrupt_level );
 608             printk( "               This shouldn't happen!\n" );
 609             printk( "               Send mail to faith@cs.unc.edu\n" );
 610          } else if (retcode == -EBUSY) {
 611             printk( "Future Domain: IRQ %d is already in use!\n",
 612                     interrupt_level );
 613             printk( "               Please use another IRQ!\n" );
 614          } else {
 615             printk( "Future Domain: Error getting IRQ %d\n", interrupt_level );
 616             printk( "               This shouldn't happen!\n" );
 617             printk( "               Send mail to faith@cs.unc.edu\n" );
 618          }
 619          printk( "               COMMAND QUEUEING DISABLED!\n" );
 620          
 621          can_queue = scsi_hosts[this_host].can_queue = 0;
 622          scsi_hosts[this_host].sg_tablesize = SG_NONE;
 623       } else {
 624          printk( "Future Domain: IRQ %d requested from kernel\n",
 625                  interrupt_level );
 626       }
 627    }
 628    
 629    return 1;
 630 }
 631 
 632 const char *fdomain_16x0_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 633 {
 634    static char buffer[] =
 635          "Future Domain TMC-16x0 SCSI driver version "
 636          VERSION
 637          "\n";
 638    return buffer;
 639 }
 640 
 641 static int fdomain_arbitrate( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 642 {
 643    int           status = 0;
 644    unsigned long timeout;
 645 
 646 #if EVERY_ACCESS
 647    printk( "SCSI: fdomain_arbitrate()\n" );
 648 #endif
 649    
 650    outb( 0x00, SCSI_Cntl_port );              /* Disable data drivers */
 651    outb( 0x40, port_base + SCSI_Data_NoACK ); /* Set our id bit */
 652    outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
 653 
 654    timeout = jiffies + 50;                    /* 500 mS */
 655    while (jiffies < timeout) {
 656       status = inb( TMC_Status_port );        /* Read adapter status */
 657       if (status & 0x02) return 0;            /* Arbitration complete */
 658    }
 659 
 660    /* Make bus idle */
 661    fdomain_make_bus_idle();
 662 
 663 #if EVERY_ACCESS
 664    printk( "Arbitration failed, status = %x\n", status );
 665 #endif
 666 #if ERRORS_ONLY
 667    printk( "SCSI (Future Domain): Arbitration failed, status = %x",
 668            status );
 669 #endif
 670    return 1;
 671 }
 672 
 673 static int fdomain_select( int target )
     /* [previous][next][first][last][top][bottom][index][help] */
 674 {
 675    int           status;
 676    unsigned long timeout;
 677 
 678    /* Send our address OR'd with target address */
 679    outb( 0x40 | (1 << target), SCSI_Data_NoACK_port );
 680 
 681    if (RESELECTION && can_queue)
 682          outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */
 683    else
 684          outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
 685 
 686    /* Stop arbitration (also set FIFO for output and enable parity) */
 687    outb( 0xc0 | PARITY_MASK, TMC_Cntl_port ); 
 688 
 689    timeout = jiffies + 25;              /* 250mS */
 690    while (jiffies < timeout) {
 691       status = inb( SCSI_Status_port ); /* Read adapter status */
 692       if (status & 1) {                 /* Busy asserted */
 693          /* Enable SCSI Bus (on error, should make bus idle with 0) */
 694          outb( 0x80, SCSI_Cntl_port );
 695          return 0;
 696       }
 697    }
 698    /* Make bus idle */
 699    fdomain_make_bus_idle();
 700 #if EVERY_ACCESS
 701    if (!target) printk( "Selection failed\n" );
 702 #endif
 703 #if ERRORS_ONLY
 704    if (!target) printk( "SCSI (Future Domain): Selection failed" );
 705 #endif
 706    return 1;
 707 }
 708 
 709 void my_done( int error )
     /* [previous][next][first][last][top][bottom][index][help] */
 710 {
 711    if (in_command) {
 712       in_command = 0;
 713       outb( 0x00, Interrupt_Cntl_port );
 714       fdomain_make_bus_idle();
 715       current_SC->result = error;
 716       if (current_SC->scsi_done) current_SC->scsi_done( current_SC );
 717       else panic( "SCSI (Future Domain): current_SC->scsi_done() == NULL" );
 718    } else {
 719       panic( "SCSI (Future Domain): my_done() called outside of command\n" );
 720    }
 721 #if DEBUG_RACE
 722    in_interrupt_flag = 0;
 723 #endif
 724 }
 725 
 726 void fdomain_16x0_intr( int unused )
     /* [previous][next][first][last][top][bottom][index][help] */
 727 {
 728    int      status;
 729    int      done = 0;
 730    unsigned data_count;
 731 
 732    sti();
 733    
 734    outb( 0x00, Interrupt_Cntl_port );
 735 
 736    /* We usually have one spurious interrupt after each command.  Ignore it. */
 737    if (!in_command || !current_SC) {    /* Spurious interrupt */
 738       return;
 739    }
 740 #if DEBUG_RACE
 741    ++in_interrupt_flag;
 742 #endif
 743 
 744    if (current_SC->SCp.phase & aborted) {
 745 #if EVERY_ACCESS
 746       if (current_SC->SCp.phase & (in_other || disconnect))
 747             printk( "aborted (%s) = %d, ",
 748                     current_SC->SCp.phase & in_other
 749                     ? "in_other" : "disconnect",
 750                     current_SC->result );
 751       else
 752             printk( "aborted = %d, ",
 753                     current_SC->result );
 754 #endif
 755       /* Force retry for timeouts after selection complete */
 756       if (current_SC->SCp.phase & (in_other || disconnect)) {
 757          fdomain_16x0_reset();
 758          my_done( DID_RESET << 16 );
 759       } else {
 760          my_done( current_SC->result << 16 );
 761       }
 762       return;
 763    }
 764 
 765 #if RESELECTION
 766    if (current_SC->SCp.phase & disconnect) {
 767       printk( " RECON %x ", inb( SCSI_Data_NoACK_port ) );
 768       current_SC->SCp.phase = in_other;
 769       outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
 770       outb( 0x84, SCSI_Cntl_port );
 771       while ( (status = inb( SCSI_Status_port )) & 0x20 ) {
 772          printk( "s = %x, ", status );
 773       }
 774       outb( 0x80, SCSI_Cntl_port );
 775    } else
 776 #endif
 777          
 778    if (current_SC->SCp.phase & in_arbitration) {
 779       status = inb( TMC_Status_port );        /* Read adapter status */
 780       if (!(status & 0x02)) {
 781 #if EVERY_ACCESS
 782          printk( " AFAIL " );
 783 #endif
 784          my_done( DID_BUS_BUSY << 16 );
 785          return;
 786       }
 787       current_SC->SCp.phase = in_selection;
 788       
 789       outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port );
 790       
 791       outb( 0x40 | (1 << current_SC->target), SCSI_Data_NoACK_port );
 792       
 793 #if RESELECTION
 794       outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */
 795 #else
 796       outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
 797 #endif
 798       
 799       /* Stop arbitration (also set FIFO for output and enable parity) */
 800       outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
 801 #if DEBUG_RACE
 802       in_interrupt_flag = 0;
 803 #endif
 804       return;
 805    } else if (current_SC->SCp.phase & in_selection) {
 806       status = inb( SCSI_Status_port );
 807       if (!(status & 0x01)) {
 808          /* Try again, for slow devices */
 809          if (fdomain_select( current_SC->target )) {
 810 #if EVERY_ACCESS
 811             printk( " SFAIL " );
 812 #endif
 813             my_done( DID_NO_CONNECT << 16 );
 814             return;
 815          } else {
 816 #if EVERY_ACCESS
 817             printk( " AltSel " );
 818 #endif
 819             /* Stop arbitration (also set FIFO for output and enable parity) */
 820             outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
 821          }
 822       }
 823       current_SC->SCp.phase = in_other;
 824       outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
 825 #if RESELECTION
 826       outb( 0x88, SCSI_Cntl_port );
 827 #else
 828       outb( 0x80, SCSI_Cntl_port );
 829 #endif
 830 #if DEBUG_RACE
 831       in_interrupt_flag = 0;
 832 #endif
 833       return;
 834    }
 835    
 836    /* current_SC->SCp.phase == in_other: this is the body of the routine */
 837    
 838    switch (current_SC->cmnd[0]) {
 839    case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
 840    case 0x2e: case 0x3b: case 0xea: case 0x3f:
 841       while ( (data_count = 0x2000 - inw( FIFO_Data_Count_port )) > 512 ) {
 842 #if EVERY_ACCESS
 843          printk( "DC=%d, ", data_count ) ;
 844 #endif
 845          if (data_count > current_SC->SCp.this_residual)
 846                data_count = current_SC->SCp.this_residual;
 847          if (data_count > 0) {
 848 #if EVERY_ACCESS
 849             printk( "%d OUT, ", data_count );
 850 #endif
 851             if (data_count == 1) {
 852                outb( *current_SC->SCp.ptr++, Write_FIFO_port );
 853                --current_SC->SCp.this_residual;
 854             } else {
 855                data_count >>= 1;
 856                outsw( current_SC->SCp.ptr, data_count, Write_FIFO_port );
 857                current_SC->SCp.ptr += 2 * data_count;
 858                current_SC->SCp.this_residual -= 2 * data_count;
 859             }
 860          }
 861          if (!current_SC->SCp.this_residual) {
 862             if (current_SC->SCp.buffers_residual) {
 863                --current_SC->SCp.buffers_residual;
 864                ++current_SC->SCp.buffer;
 865                current_SC->SCp.ptr = current_SC->SCp.buffer->address;
 866                current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
 867             } else
 868                   break;
 869          }
 870       }
 871       break;
 872    default:
 873       if (!current_SC->SCp.have_data_in) {
 874          outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
 875          ++current_SC->SCp.have_data_in;
 876       } else {
 877          while ((data_count = inw( FIFO_Data_Count_port )) != 0) {
 878 #if EVERY_ACCESS
 879             printk( "DC=%d, ", data_count );
 880 #endif
 881             if (data_count > current_SC->SCp.this_residual)
 882                   data_count = current_SC->SCp.this_residual;
 883             if (data_count) {
 884 #if EVERY_ACCESS
 885                printk( "%d IN, ", data_count );
 886 #endif
 887                if (data_count == 1) {
 888                   *current_SC->SCp.ptr++ = inb( Read_FIFO_port );
 889                   --current_SC->SCp.this_residual;
 890                } else {
 891                   data_count >>= 1; /* Number of words */
 892                   insw( current_SC->SCp.ptr, data_count, Read_FIFO_port );
 893                   current_SC->SCp.ptr += 2 * data_count;
 894                   current_SC->SCp.this_residual -= 2 * data_count;
 895                }
 896             }
 897             if (!current_SC->SCp.this_residual
 898                 && current_SC->SCp.buffers_residual) {
 899                --current_SC->SCp.buffers_residual;
 900                ++current_SC->SCp.buffer;
 901                current_SC->SCp.ptr = current_SC->SCp.buffer->address;
 902                current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
 903             }
 904          }
 905       }
 906       break;
 907    }
 908    
 909    status = inb( SCSI_Status_port );
 910    
 911    if (status & 0x10) { /* REQ */
 912       
 913       switch (status & 0x0e) {
 914       case 0x08:                /* COMMAND OUT */
 915 #if 0
 916          if (!current_SC->SCp.sent_command) {
 917             int i;
 918             
 919             ++current_SC->SCp.sent_command;
 920             
 921             for (i = 0; i < COMMAND_SIZE( current_SC->cmnd[0] ); i++) {
 922                outb( current_SC->cmnd[i], Write_SCSI_Data_port );
 923 #if EVERY_ACCESS
 924                printk( "CMD = %x,", current_SC->cmnd[i] );
 925 #endif
 926             }
 927          }
 928 #else
 929          outb( current_SC->cmnd[current_SC->SCp.sent_command++],
 930                Write_SCSI_Data_port );
 931 #if EVERY_ACCESS
 932          printk( "CMD = %x,",
 933                  current_SC->cmnd[ current_SC->SCp.sent_command - 1] );
 934 #endif
 935          
 936 #endif
 937          break;
 938       case 0x0c:                /* STATUS IN */
 939          current_SC->SCp.Status = inb( Read_SCSI_Data_port );
 940 #if EVERY_ACCESS
 941          printk( "Status = %x, ", current_SC->SCp.Status );
 942 #endif
 943 #if ERRORS_ONLY
 944          if (current_SC->SCp.Status && current_SC->SCp.Status != 2) {
 945             printk( "SCSI (Future Domain): target = %d, command = %x, "
 946                     "Status = %x\n",
 947                     current_SC->target, current_SC->cmnd[0],
 948                     current_SC->SCp.Status );
 949          }
 950 #endif
 951                break;
 952       case 0x0a:                /* MESSAGE OUT */
 953 #if RESELECTION
 954          if (!(current_SC->SCp.phase & sent_ident)) {
 955 #if EVERY_ACCESS
 956             printk( " IDENT " );
 957 #endif
 958             outb( 0x80, SCSI_Cntl_port );
 959             outb( IDENTIFY( 1, 0 ), Write_SCSI_Data_port );
 960             current_SC->SCp.phase |= sent_ident;
 961          } else
 962 #else
 963                outb( MESSAGE_REJECT, Write_SCSI_Data_port ); /* Reject */
 964 #endif
 965          break;
 966       case 0x0e:                /* MESSAGE IN */
 967          current_SC->SCp.Message = inb( Read_SCSI_Data_port );
 968 #if EVERY_ACCESS
 969          printk( "Message = %x, ", current_SC->SCp.Message );
 970 #endif
 971          if (!current_SC->SCp.Message) ++done;
 972 #if RESELECTION
 973          if (current_SC->SCp.Message == DISCONNECT) {
 974             printk( " DISCON " );
 975             current_SC->SCp.phase = disconnect;
 976          }
 977 #endif
 978 #if DEBUG_MESSAGES || EVERY_ACCESS
 979          if (current_SC->SCp.Message) {
 980             printk( "SCSI (Future Domain): Message = %x\n",
 981                     current_SC->SCp.Message );
 982          }
 983 #endif
 984          break;
 985       }
 986    }
 987    
 988    if (done) {
 989 #if EVERY_ACCESS
 990       printk( " ** IN DONE ** " );
 991 #endif
 992 
 993       if (current_SC->SCp.have_data_in) {
 994          while ((data_count = inw( FIFO_Data_Count_port )) != 0) {
 995             if (data_count > current_SC->SCp.this_residual)
 996                   data_count = current_SC->SCp.this_residual;
 997 
 998             if (data_count) {
 999 #if EVERY_ACCESS
1000                printk( "%d IN, ", data_count );
1001 #endif
1002                if (data_count == 1) {
1003                   *current_SC->SCp.ptr++ = inb( Read_FIFO_port );
1004                   --current_SC->SCp.this_residual;
1005                } else {
1006                   data_count >>= 1; /* Number of words */
1007                   insw( current_SC->SCp.ptr, data_count, Read_FIFO_port );
1008                   current_SC->SCp.this_residual -= 2 * data_count;
1009                }
1010             }
1011             
1012             if (!current_SC->SCp.this_residual
1013                 && current_SC->SCp.buffers_residual) {
1014                
1015                --current_SC->SCp.buffers_residual;
1016                ++current_SC->SCp.buffer;
1017                current_SC->SCp.ptr = current_SC->SCp.buffer->address;
1018                current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
1019             }
1020          }
1021       }
1022 #if EVERY_ACCESS
1023       printk( "AFTER DATA GET\n" );
1024 #endif
1025       
1026 #if ERRORS_ONLY
1027       if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
1028          if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) {
1029             unsigned char key;
1030             unsigned char code;
1031 
1032             key = (unsigned char)(*((char *)current_SC->request_buffer + 2))
1033                   & 0x0f;
1034             code = (unsigned char)(*((char *)current_SC->request_buffer + 12));
1035 
1036             if (!(key == UNIT_ATTENTION && (code == 0x29 || !code))
1037                 && !(key == ILLEGAL_REQUEST && (code == 0x25 || !code)))
1038                   
1039                   printk( "SCSI REQUEST SENSE: Key = %x, Code = %x\n",
1040                           key, code );
1041          }
1042       }
1043 #endif
1044 #if EVERY_ACCESS
1045       printk( "BEFORE MY_DONE. . ." );
1046 #endif
1047       my_done( (current_SC->SCp.Status & 0xff)
1048                | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
1049 #if EVERY_ACCESS
1050       printk( "RETURNING.\n" );
1051 #endif
1052       
1053    } else {
1054       if (current_SC->SCp.phase & disconnect) {
1055          outb( 0xd0 | FIFO_COUNT, Interrupt_Cntl_port );
1056          outb( 0x00, SCSI_Cntl_port );
1057       } else {
1058          outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
1059       }
1060    }
1061 #if DEBUG_RACE
1062    in_interrupt_flag = 0;
1063 #endif
1064    return;
1065 }
1066 
1067 int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
1068 {
1069    if (in_command) {
1070       panic( "SCSI (Future Domain): fdomain_16x0_queue() NOT REENTRANT!\n" );
1071    }
1072 #if EVERY_ACCESS
1073    printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
1074            SCpnt->target,
1075            *(unsigned char *)SCpnt->cmnd,
1076            SCpnt->use_sg,
1077            SCpnt->request_bufflen );
1078 #endif
1079 
1080    fdomain_make_bus_idle();
1081 
1082    current_SC            = SCpnt; /* Save this for the done function */
1083    current_SC->scsi_done = done;
1084 
1085    /* Initialize static data */
1086 
1087    if (current_SC->use_sg) {
1088       current_SC->SCp.buffer =
1089             (struct scatterlist *)current_SC->request_buffer;
1090       current_SC->SCp.ptr              = current_SC->SCp.buffer->address;
1091       current_SC->SCp.this_residual    = current_SC->SCp.buffer->length;
1092       current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
1093    } else {
1094       current_SC->SCp.ptr              = current_SC->request_buffer;
1095       current_SC->SCp.this_residual    = current_SC->request_bufflen;
1096       current_SC->SCp.buffer           = NULL;
1097       current_SC->SCp.buffers_residual = 0;
1098    }
1099          
1100    
1101    current_SC->SCp.Status              = 0;
1102    current_SC->SCp.Message             = 0;
1103    current_SC->SCp.have_data_in        = 0;
1104    current_SC->SCp.sent_command        = 0;
1105    current_SC->SCp.phase               = in_arbitration;
1106 
1107    /* Start arbitration */
1108    outb( 0x00, Interrupt_Cntl_port );
1109    outb( 0x00, SCSI_Cntl_port );              /* Disable data drivers */
1110    outb( 0x40, SCSI_Data_NoACK_port );        /* Set our id bit */
1111    ++in_command;
1112    outb( 0x20, Interrupt_Cntl_port );
1113    outb( 0x14 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
1114 
1115    return 0;
1116 }
1117 
1118 int fdomain_16x0_command( Scsi_Cmnd *SCpnt )
     /* [previous][next][first][last][top][bottom][index][help] */
1119 {
1120    const char     *cmd_pt      = SCpnt->cmnd;
1121    const char     *the_command = SCpnt->cmnd;
1122    unsigned char  *out_buf_pt  = SCpnt->request_buffer;
1123    unsigned char  *in_buf_pt   = SCpnt->request_buffer;
1124    unsigned char  target       = SCpnt->target;
1125    void           *buff        = SCpnt->request_buffer;
1126    int            bufflen      = SCpnt->request_bufflen;
1127    int            Status       = 0;
1128    int            Message      = 0;
1129    int            status;
1130    int            done         = 0;
1131    unsigned long  timeout;
1132    unsigned       data_sent    = 0;
1133    unsigned       data_count;
1134    int            have_data_in = 0;
1135 
1136    current_SC = SCpnt;
1137 
1138 #if EVERY_ACCESS
1139    printk( "fdomain_command(%d, %x): ", target, (unsigned char)*the_command );
1140 #endif
1141 
1142    if (fdomain_arbitrate()) {
1143 #if ERRORS_ONLY
1144       printk( ", target = %d, command = %x\n",
1145               target, (unsigned char)*the_command );
1146 #endif
1147       return DID_TIME_OUT << 16;
1148    }
1149 
1150    if (fdomain_select( target )) {
1151 #if ERRORS_ONLY
1152       if (!target) printk( ", target = %d, command = %x\n",
1153                            target, (unsigned char)*the_command );
1154 #endif
1155       return DID_NO_CONNECT << 16;
1156    }
1157 
1158    timeout = jiffies + 500;     /* 5000 mS -- For Maxtor after a RST */
1159    current_SC->SCp.phase = non_queueing;
1160 
1161    switch ((unsigned char)*the_command) {
1162    case 0x04: case 0x07: case 0x0a: case 0x15: case 0x2a:
1163    case 0x2e: case 0x3b: case 0xea: case 0x3f:
1164       data_count = 0x2000 - inw( FIFO_Data_Count_port );
1165       if (bufflen - data_sent < data_count)
1166             data_count = bufflen - data_sent;
1167       if (data_count == 1) {
1168          outb( *out_buf_pt++, Write_FIFO_port );
1169          ++data_sent;
1170       } else {
1171          data_count >>= 1;
1172          outsw( out_buf_pt, data_count, Write_FIFO_port );
1173          out_buf_pt += 2 * data_count;
1174          data_sent += 2 * data_count;
1175       }
1176       break;
1177    default:
1178       outb( 0x80 | PARITY_MASK, TMC_Cntl_port );
1179       ++have_data_in;
1180       break;
1181    }
1182    
1183    while (((status = inb( SCSI_Status_port )) & 1)
1184           && !done && !(current_SC->SCp.phase & aborted)
1185           && jiffies < timeout) {
1186       
1187       if (status & 0x10) {      /* REQ */
1188 
1189          switch (status & 0x0e) {
1190          case 0x00:             /* DATA OUT */
1191             data_count = 0x2000 - inw( FIFO_Data_Count_port );
1192             if (bufflen - data_sent < data_count)
1193                   data_count = bufflen - data_sent;
1194             if (data_count == 1) {
1195                outb( *out_buf_pt++, Write_FIFO_port );
1196                ++data_sent;
1197             } else {
1198                data_count >>= 1;
1199                outsw( out_buf_pt, data_count, Write_FIFO_port );
1200                out_buf_pt += 2 * data_count;
1201                data_sent += 2 * data_count;
1202             }
1203             break;
1204          case 0x04:             /* DATA IN */
1205             if (!have_data_in) {
1206                outb( 0x80 | PARITY_MASK, TMC_Cntl_port );
1207                ++have_data_in;
1208             }
1209             data_count = inw( FIFO_Data_Count_port );
1210             if (data_count == 1) {
1211                *in_buf_pt++ = inb( Read_FIFO_port );
1212             } else {
1213                data_count >>= 1; /* Number of words */
1214                insw( in_buf_pt, data_count, Read_FIFO_port );
1215                in_buf_pt += 2 * data_count;
1216             }
1217             break;
1218          case 0x08:             /* COMMAND OUT */
1219             outb( *cmd_pt++, Write_SCSI_Data_port );
1220 #if EVERY_ACCESS
1221             printk( "%x,", (unsigned char)cmd_pt[-1] );
1222 #endif
1223             break;
1224          case 0x0c:             /* STATUS IN */
1225             Status = inb( Read_SCSI_Data_port );
1226 #if EVERY_ACCESS
1227             printk( "Status = %x, ", Status );
1228 #endif
1229 #if ERRORS_ONLY
1230             if (Status) {
1231                printk( "SCSI (Future Domain): target = %d, command = %x, "
1232                        "Status = %x\n",
1233                        target, (unsigned char)*the_command, Status );
1234             }
1235 #endif
1236             break;
1237          case 0x0a:             /* MESSAGE OUT */
1238             outb( 0x07, Write_SCSI_Data_port ); /* Reject */
1239             break;
1240          case 0x0e:             /* MESSAGE IN */
1241             Message = inb( Read_SCSI_Data_port );
1242 #if EVERY_ACCESS
1243             printk( "Message = %x, ", Message );
1244 #endif
1245             if (!Message) ++done;
1246             if (Message == DISCONNECT) printk( "DISCONNECT\n" );
1247             break;
1248          }
1249       }
1250    }
1251 
1252    if (jiffies >= timeout) {
1253 #if EVERY_ACCESS
1254       printk( "Time out, status = %x\n", status );
1255 #endif
1256 #if ERRORS_ONLY
1257       printk( "SCSI (Future Domain): "
1258               "Time out, status = %x (target = %d, command = %x)\n",
1259               status, target, (unsigned char)*the_command );
1260 #endif
1261       fdomain_make_bus_idle();
1262       return DID_BUS_BUSY << 16;
1263    }
1264 
1265    if (current_SC->SCp.phase & aborted) {
1266 #if EVERY_ACCESS
1267       printk( "Aborted\n" );
1268 #endif
1269 #if ERRORS_ONLY
1270       printk( "SCSI (Future Domain): Aborted (command = %x)\n",
1271               (unsigned char)*the_command );
1272 #endif
1273       fdomain_16x0_reset();
1274       return DID_RESET << 16;
1275    }
1276    
1277    if (have_data_in) {
1278       while ((data_count = inw( FIFO_Data_Count_port )) != 0) {
1279          if (data_count == 1) {
1280             *in_buf_pt++ = inb( Read_FIFO_port );
1281          } else {
1282             data_count >>= 1; /* Number of words */
1283             insw( in_buf_pt, data_count, Read_FIFO_port );
1284             in_buf_pt += 2 * data_count;
1285          }
1286       }
1287    }
1288 
1289    fdomain_make_bus_idle();
1290 
1291 #if EVERY_ACCESS
1292    printk( "Retcode = %x\n",
1293            (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16) );
1294 #endif
1295 #if ERRORS_ONLY
1296    if (*the_command == REQUEST_SENSE && !Status) {
1297       if ((unsigned char)(*((char *)buff + 2)) & 0x0f) {
1298          printk( "SCSI REQUEST SENSE: Sense Key = %x, Sense Code = %x\n",
1299                  (unsigned char)(*((char *)buff + 2)) & 0x0f,
1300                  (unsigned char)(*((char *)buff + 12)) );
1301       }
1302    }
1303 #endif
1304 
1305    return (Status & 0xff) | ((Message & 0xff) << 8) | (DID_OK << 16);
1306 }
1307 
1308 int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code )
     /* [previous][next][first][last][top][bottom][index][help] */
1309 {
1310 
1311 #if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
1312    printk( "SCSI (Future Domain): Abort " );
1313 #endif
1314 
1315 #if DEBUG_ABORT
1316    print_banner();
1317    switch (current_SC->SCp.phase) {
1318    case non_queueing:   printk( "nonqueueing " ); break;
1319    case in_arbitration: printk( "arbitration " ); break;
1320    case in_selection:   printk( "selection " );   break;
1321    case in_other:       printk( "other " );       break;
1322    default:             printk( "unknown " );     break;
1323    }
1324 
1325    printk( "phase = %d, target = %d cmnd = 0x%02x pieces = %d size = %u\n",
1326            current_SC->SCp.phase,
1327            current_SC->target,
1328            *(unsigned char *)current_SC->cmnd,
1329            current_SC->use_sg,
1330            current_SC->request_bufflen );
1331 #if DEBUG_RACE
1332    printk( "in_interrupt_flag = %d\n", in_interrupt_flag );
1333 #endif
1334    printk( "IMR = 0x%02x%02x\n", inb( 0x0a1 ), inb( 0x21 ) );
1335    outb( 0x0a, 0xa0 );
1336    printk( "IRR = 0x%02x", inb( 0xa0 ) );
1337    outb( 0x0a, 0x20 );
1338    printk( "%02x\n", inb( 0x20 ) );
1339    outb( 0x0b, 0xa0 );
1340    printk( "ISR = 0x%02x", inb( 0xa0 ) );
1341    outb( 0x0b, 0x20 );
1342    printk( "%02x\n", inb( 0x20 ) );
1343    printk( "SCSI Status    = %x\n", inb( SCSI_Status_port ) );
1344    printk( "TMC Status     = %x\n", inb( TMC_Status_port ) );
1345    printk( "Interrupt Mask = %x\n", inb( Interrupt_Mask_port ) );
1346    printk( "Option Select  = %x\n", inb( port_base + Option_Select ) );
1347    if (chip == tmc18c50) {
1348       printk( "FIFO Status    = %x\n", inb( port_base + FIFO_Status ) );
1349       printk( "Int. Condition = %x\n", inb( port_base + Interrupt_Cond ) );
1350       printk( "Configuration  = %x\n", inb( port_base + Configuration ) );
1351    }
1352 #else
1353    cli();
1354    if (!in_command) {
1355 #if EVERY_ACCESS || ERRORS_ONLY
1356       printk( " (not in command)\n" );
1357 #endif
1358       sti();
1359       return 0;
1360    } else {
1361 #if EVERY_ACCESS || ERRORS_ONLY
1362       printk( " code = %d\n", code );
1363 #endif
1364    }
1365 
1366    current_SC->SCp.phase |= aborted;
1367 
1368    current_SC->result = code ? code : DID_ABORT;
1369 
1370    sti();
1371    
1372    /* Aborts are not done well. . . */
1373    my_done( code << 16 );
1374 #endif
1375    return 0;
1376 }
1377 
1378 int fdomain_16x0_reset( void )
     /* [previous][next][first][last][top][bottom][index][help] */
1379 {
1380 #if ERRORS_ONLY
1381    printk( "Future Domain: SCSI Bus Reset\n" );
1382 #endif
1383    outb( 1, SCSI_Cntl_port );
1384    do_pause( 2 );
1385    outb( 0, SCSI_Cntl_port );
1386    do_pause( 115 );
1387    outb( 0, Data_Mode_Cntl_port );
1388    outb( PARITY_MASK, TMC_Cntl_port );
1389    return 0;
1390 }
1391 
1392 int fdomain_16x0_biosparam( int size, int dev, int *info )
     /* [previous][next][first][last][top][bottom][index][help] */
1393 {
1394    int    drive;
1395    struct drive_info {
1396       unsigned short cylinders;
1397       unsigned char  heads;
1398       unsigned char  sectors;
1399    } *i;
1400    
1401    /* NOTES:
1402       The RAM area starts at 0x1f00 from the bios_base address.
1403       The drive parameter table seems to start at 0x1f30.
1404       The first byte's purpose is not known.
1405       Next is the cylinder, head, and sector information.
1406       The last 4 bytes appear to be the drive's size in sectors.
1407       The other bytes in the drive parameter table are unknown.
1408       If anyone figures them out, please send me mail, and I will
1409       update these notes.
1410 
1411       Tape drives do not get placed in this table.
1412 
1413       There is another table at 0x1fea:
1414       If the byte is 0x01, then the SCSI ID is not in use.
1415       If the byte is 0x18 or 0x48, then the SCSI ID is in use,
1416       although tapes don't seem to be in this table.  I haven't
1417       seen any other numbers (in a limited sample).
1418 
1419       0x1f2d is a drive count (i.e., not including tapes)
1420 
1421       The table at 0x1fcc are I/O ports addresses for the various
1422       operations.  I calculate these by hand in this driver code.
1423     */
1424 
1425    drive = MINOR(dev) / 16;
1426    i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 );
1427    info[0] = i->heads;
1428    info[1] = i->sectors;
1429    info[2] = i->cylinders;
1430    return 0;
1431 }

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