root/drivers/scsi/fdomain.c

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

DEFINITIONS

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

   1 /* fdomain.c -- Future Domain TMC-16x0 SCSI driver
   2  * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
   3  * Revised: Mon Jun  5 09:21:54 1995 by faith@cs.unc.edu
   4  * Author: Rickard E. Faith, faith@cs.unc.edu
   5  * Copyright 1992, 1993, 1994, 1995 Rickard E. Faith
   6  *
   7  * $Id: fdomain.c,v 5.28 1995/06/05 13:21:57 faith Exp $
   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  * You should have received a copy of the GNU General Public License along
  20  * with this program; if not, write to the Free Software Foundation, Inc.,
  21  * 675 Mass Ave, Cambridge, MA 02139, USA.
  22 
  23  **************************************************************************
  24  
  25  DESCRIPTION:
  26 
  27  This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
  28  TMC-1650/1670, and TMC-3260 SCSI host adapters.  The 1650 and 1670 have a
  29  25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin
  30  high-density external connector.  The 1670 and 1680 have floppy disk
  31  controllers built in.  The TMC-3260 is a PCI bus card.
  32 
  33  Future Domain's older boards are based on the TMC-1800 chip, and this
  34  driver was originally written for a TMC-1680 board with the TMC-1800 chip.
  35  More recently, boards are being produced with the TMC-18C50 and TMC-18C30
  36  chips.  The latest and greatest board may not work with this driver.  If
  37  you have to patch this driver so that it will recognize your board's BIOS
  38  signature, then the driver may fail to function after the board is
  39  detected.
  40 
  41  The following BIOS versions are supported: 2.0, 3.0, 3.2, 3.4, and 3.5.
  42  The following chips are supported: TMC-1800, TMC-18C50, TMC-18C30.
  43  Reports suggest that the driver will also work with the 36C70 chip and
  44  with the Quantum ISA-200S and ISA-250MG SCSI adapters.
  45 
  46  Please note that the drive ordering that Future Domain implemented in BIOS
  47  versions 3.4 and 3.5 is the opposite of the order (currently) used by the
  48  rest of the SCSI industry.  If you have BIOS version 3.4 or 3.5, and have
  49  more then one drive, then the drive ordering will be the reverse of that
  50  which you see under DOS.  For example, under DOS SCSI ID 0 will be D: and
  51  SCSI ID 1 will be C: (the boot device).  Under Linux, SCSI ID 0 will be
  52  /dev/sda and SCSI ID 1 will be /dev/sdb.  The Linux ordering is consistent
  53  with that provided by all the other SCSI drivers for Linux.  If you want
  54  this changed, send me patches that are protected by #ifdefs.
  55 
  56  If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
  57  your board.  Please refer to the Seagate driver for more information and
  58  possible support.
  59 
  60  
  61 
  62  REFERENCES USED:
  63 
  64  "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation,
  65  1990.
  66 
  67  "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain
  68  Corporation, January 1992.
  69 
  70  "LXT SCSI Products: Specifications and OEM Technical Manual (Revision
  71  B/September 1991)", Maxtor Corporation, 1991.
  72 
  73  "7213S product Manual (Revision P3)", Maxtor Corporation, 1992.
  74 
  75  "Draft Proposed American National Standard: Small Computer System
  76  Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109,
  77  revision 10h, October 17, 1991)
  78 
  79  Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric
  80  Youngdale (ericy@cais.com), 1992.
  81 
  82  Private communication, Tuong Le (Future Domain Engineering department),
  83  1994. (Disk geometry computations for Future Domain BIOS version 3.4, and
  84  TMC-18C30 detection.)
  85 
  86  Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page
  87  60 (2.39: Disk Partition Table Layout).
  88 
  89  "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page
  90  6-1.
  91 
  92 
  93  
  94  NOTES ON REFERENCES:
  95 
  96  The Maxtor manuals were free.  Maxtor telephone technical support is
  97  great!
  98 
  99  The Future Domain manuals were $25 and $35.  They document the chip, not
 100  the TMC-16x0 boards, so some information I had to guess at.  In 1992,
 101  Future Domain sold DOS BIOS source for $250 and the UN*X driver source was
 102  $750, but these required a non-disclosure agreement, so even if I could
 103  have afforded them, they would *not* have been useful for writing this
 104  publically distributable driver.  Future Domain technical support has
 105  provided some information on the phone and have sent a few useful FAXs.
 106  They have been much more helpful since they started to recognize that the
 107  word "Linux" refers to an operating system :-).
 108 
 109  
 110 
 111  ALPHA TESTERS:
 112 
 113  There are many other alpha testers that come and go as the driver
 114  develops.  The people listed here were most helpful in times of greatest
 115  need (mostly early on -- I've probably left out a few worthy people in
 116  more recent times):
 117 
 118  Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken
 119  Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@bruin@sterbbs.nl), Sakari
 120  Aaltonen (sakaria@vipunen.hit.fi), John Rice (rice@xanth.cs.odu.edu), Brad
 121  Yearwood (brad@optilink.com), and Ray Toy (toy@soho.crd.ge.com).
 122 
 123  Special thanks to Tien-Wan Yang (twyang@cs.uh.edu), who graciously lent me
 124  his 18C50-based card for debugging.  He is the sole reason that this
 125  driver works with the 18C50 chip.
 126 
 127  Thanks to Dave Newman (dnewman@crl.com) for providing initial patches for
 128  the version 3.4 BIOS.
 129 
 130  Thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for providing
 131  patches that support the TMC-3260, a PCI bus card with the 36C70 chip.
 132  The 36C70 chip appears to be "completely compatible" with the 18C30 chip.
 133 
 134  Thanks to Eric Kasten (tigger@petroglyph.cl.msu.edu) for providing the
 135  patch for the version 3.5 BIOS.
 136 
 137  Thanks for Stephen Henson (shenson@nyx10.cs.du.edu) for providing the
 138  patch for the Quantum ISA-200S SCSI adapter.
 139  
 140  Thanks to Adam Bowen for the signature to the 1610M/MER/MEX scsi cards,
 141  and to Martin Andrews (andrewm@ccfadm.eeg.ccf.org) for the signature to
 142  some random TMC-1680 repackaged by IBM.
 143 
 144  Thanks for Mark Singer (elf@netcom.com) and Richard Simpson
 145  (rsimpson@ewrcsdra.demon.co.uk) for more Quantum signatures and detective
 146  work on the Quantum RAM layout.
 147 
 148  All of the alpha testers deserve much thanks.
 149 
 150 
 151 
 152  NOTES ON USER DEFINABLE OPTIONS:
 153 
 154  DEBUG: This turns on the printing of various debug information.
 155 
 156  ENABLE_PARITY: This turns on SCSI parity checking.  With the current
 157  driver, all attached devices must support SCSI parity.  If none of your
 158  devices support parity, then you can probably get the driver to work by
 159  turning this option off.  I have no way of testing this, however.
 160 
 161  FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
 162  18C30 chip have a 2k cache).  When this many 512 byte blocks are filled by
 163  the SCSI device, an interrupt will be raised.  Therefore, this could be as
 164  low as 0, or as high as 16.  Note, however, that values which are too high
 165  or too low seem to prevent any interrupts from occurring, and thereby lock
 166  up the machine.  I have found that 2 is a good number, but throughput may
 167  be increased by changing this value to values which are close to 2.
 168  Please let me know if you try any different values.
 169 
 170  DO_DETECT: This activates some old scan code which was needed before the
 171  high level drivers got fixed.  If you are having trouble with the driver,
 172  turning this on should not hurt, and might help.  Please let me know if
 173  this is the case, since this code will be removed from future drivers.
 174 
 175  RESELECTION: This is no longer an option, since I gave up trying to
 176  implement it in version 4.x of this driver.  It did not improve
 177  performance at all and made the driver unstable (because I never found one
 178  of the two race conditions which were introduced by the multiple
 179  outstanding command code).  The instability seems a very high price to pay
 180  just so that you don't have to wait for the tape to rewind.  If you want
 181  this feature implemented, send me patches.  I'll be happy to send a copy
 182  of my (broken) driver to anyone who would like to see a copy.
 183 
 184  **************************************************************************/
 185 
 186 #include <linux/sched.h>
 187 #include <asm/io.h>
 188 #include "../block/blk.h"
 189 #include "scsi.h"
 190 #include "hosts.h"
 191 #include "fdomain.h"
 192 #include <asm/system.h>
 193 #include <linux/errno.h>
 194 #include <linux/string.h>
 195 #include <linux/ioport.h>
 196 
 197 #define VERSION          "$Revision: 5.28 $"
 198 
 199 /* START OF USER DEFINABLE OPTIONS */
 200 
 201 #define DEBUG            1      /* Enable debugging output */
 202 #define ENABLE_PARITY    1      /* Enable SCSI Parity */
 203 #define FIFO_COUNT       2      /* Number of 512 byte blocks before INTR */
 204 #define DO_DETECT        0      /* Do device detection here (see scsi.c) */
 205 
 206 /* END OF USER DEFINABLE OPTIONS */
 207 
 208 #if DEBUG
 209 #define EVERY_ACCESS     0      /* Write a line on every scsi access */
 210 #define ERRORS_ONLY      1      /* Only write a line if there is an error */
 211 #define DEBUG_DETECT     0      /* Debug fdomain_16x0_detect() */
 212 #define DEBUG_MESSAGES   1      /* Debug MESSAGE IN phase */
 213 #define DEBUG_ABORT      1      /* Debug abort() routine */
 214 #define DEBUG_RESET      1      /* Debug reset() routine */
 215 #define DEBUG_RACE       1      /* Debug interrupt-driven race condition */
 216 #else
 217 #define EVERY_ACCESS     0      /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
 218 #define ERRORS_ONLY      0
 219 #define DEBUG_DETECT     0
 220 #define DEBUG_MESSAGES   0
 221 #define DEBUG_ABORT      0
 222 #define DEBUG_RESET      0
 223 #define DEBUG_RACE       0
 224 #endif
 225 
 226 /* Errors are reported on the line, so we don't need to report them again */
 227 #if EVERY_ACCESS
 228 #undef ERRORS_ONLY
 229 #define ERRORS_ONLY      0
 230 #endif
 231 
 232 #if ENABLE_PARITY
 233 #define PARITY_MASK      0x08
 234 #else
 235 #define PARITY_MASK      0x00
 236 #endif
 237 
 238 enum chip_type {
 239    unknown          = 0x00,
 240    tmc1800          = 0x01,
 241    tmc18c50         = 0x02,
 242    tmc18c30         = 0x03,
 243 };
 244 
 245 enum {
 246    in_arbitration   = 0x02,
 247    in_selection     = 0x04,
 248    in_other         = 0x08,
 249    disconnect       = 0x10,
 250    aborted          = 0x20,
 251    sent_ident       = 0x40,
 252 };
 253 
 254 enum in_port_type {
 255    Read_SCSI_Data   =  0,
 256    SCSI_Status      =  1,
 257    TMC_Status       =  2,
 258    FIFO_Status      =  3,       /* tmc18c50/tmc18c30 only */
 259    Interrupt_Cond   =  4,       /* tmc18c50/tmc18c30 only */
 260    LSB_ID_Code      =  5,
 261    MSB_ID_Code      =  6,
 262    Read_Loopback    =  7,
 263    SCSI_Data_NoACK  =  8,
 264    Interrupt_Status =  9,
 265    Configuration1   = 10,
 266    Configuration2   = 11,       /* tmc18c50/tmc18c30 only */
 267    Read_FIFO        = 12,
 268    FIFO_Data_Count  = 14
 269 };
 270 
 271 enum out_port_type {
 272    Write_SCSI_Data  =  0,
 273    SCSI_Cntl        =  1,
 274    Interrupt_Cntl   =  2,
 275    SCSI_Mode_Cntl   =  3,
 276    TMC_Cntl         =  4,
 277    Memory_Cntl      =  5,       /* tmc18c50/tmc18c30 only */
 278    Write_Loopback   =  7,
 279    IO_Control       = 11,       /* tmc18c30 only */
 280    Write_FIFO       = 12
 281 };
 282 
 283 static int               port_base         = 0;
 284 static void              *bios_base        = NULL;
 285 static int               bios_major        = 0;
 286 static int               bios_minor        = 0;
 287 static int               PCI_bus           = 0;
 288 static int               Quantum           = 0; /* Quantum board variant */
 289 static int               interrupt_level   = 0;
 290 static volatile int      in_command        = 0;
 291 static Scsi_Cmnd         *current_SC       = NULL;
 292 static enum chip_type    chip              = unknown;
 293 static int               adapter_mask      = 0x40;
 294 #if DEBUG_RACE
 295 static volatile int      in_interrupt_flag = 0;
 296 #endif
 297 
 298 static int               SCSI_Mode_Cntl_port;
 299 static int               FIFO_Data_Count_port;
 300 static int               Interrupt_Cntl_port;
 301 static int               Interrupt_Status_port;
 302 static int               Read_FIFO_port;
 303 static int               Read_SCSI_Data_port;
 304 static int               SCSI_Cntl_port;
 305 static int               SCSI_Data_NoACK_port;
 306 static int               SCSI_Status_port;
 307 static int               TMC_Cntl_port;
 308 static int               TMC_Status_port;
 309 static int               Write_FIFO_port;
 310 static int               Write_SCSI_Data_port;
 311 
 312 static int               FIFO_Size = 0x2000; /* 8k FIFO for
 313                                                 pre-tmc18c30 chips */
 314 
 315 extern void              fdomain_16x0_intr( int irq, struct pt_regs * regs );
 316 
 317 static void *addresses[] = {
 318    (void *)0xc8000,
 319    (void *)0xca000,
 320    (void *)0xce000,
 321    (void *)0xde000,
 322    (void *)0xd0000,             /* Extra addresses for PCI boards */
 323    (void *)0xe0000,
 324 };
 325 #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
 326                        
 327 static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
 328 #define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
 329 
 330 static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
 331 
 332 /*
 333 
 334   READ THIS BEFORE YOU ADD A SIGNATURE!
 335 
 336   READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME!
 337 
 338   READ EVERY WORD, ESPECIALLY THE WORD *NOT*
 339 
 340   This driver works *ONLY* for Future Domain cards using the TMC-1800,
 341   TMC-18C50, or TMC-18C30 chip.  This includes models TMC-1650, 1660, 1670,
 342   and 1680.
 343 
 344   The following BIOS signature signatures are for boards which do *NOT*
 345   work with this driver (these TMC-8xx and TMC-9xx boards may work with the
 346   Seagate driver):
 347 
 348   FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88
 349   FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89
 350   FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89
 351   FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90
 352   FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
 353   FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
 354   FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92
 355 
 356 */
 357 
 358 struct signature {
 359    char *signature;
 360    int  sig_offset;
 361    int  sig_length;
 362    int  major_bios_version;
 363    int  minor_bios_version;
 364    int  flag; /* 1 == PCI_bus, 2 == ISA_200S, 3 == ISA_250MG, 4 == ISA_200S */
 365 } signatures[] = {
 366    /*          1         2         3         4         5         6 */
 367    /* 123456789012345678901234567890123456789012345678901234567890 */
 368    { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89",  5, 50,  2,  0, 0 },
 369    { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89",  5, 50,  2,  0, 0 },
 370    { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50,  2,  0, 2 },
 371    { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0",        73, 43,  2,  0, 3 },
 372    { "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.",            72, 39,  2,  0, 4 },
 373    { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92",        5, 44,  3,  0, 0 },
 374    { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93",        5, 44,  3,  2, 0 },
 375    { "IBM F1 P2 BIOS v1.0104/29/93",                        5, 28,  3, -1, 0 },
 376    { "Future Domain Corp. V1.0008/18/93",                   5, 33,  3,  4, 0 },
 377    { "Future Domain Corp. V1.0008/18/93",                  26, 33,  3,  4, 1 },
 378                                 /* This next signature may not be a 3.5 bios */
 379    { "Future Domain Corp. V2.0108/18/93",                   5, 33,  3,  5, 0 },
 380    { "FUTURE DOMAIN CORP.  V3.5008/18/93",                  5, 34,  3,  5, 0 },
 381    { "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5",        5, 44,  3,  5, 0 },
 382    { "FUTURE DOMAIN TMC-18XX",                              5, 22, -1, -1, 0 },
 383 
 384    /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGNATURE
 385     Also, fix the disk geometry code for your signature and send your
 386     changes for faith@cs.unc.edu.  Above all, do *NOT* change any old
 387     signatures!
 388 
 389     Note that the last line will match a "generic" 18XX bios.  Because
 390     Future Domain has changed the host SCSI ID and/or the location of the
 391     geometry information in the on-board RAM area for each of the first
 392     three BIOS's, it is still important to enter a fully qualified
 393     signature in the table for any new BIOS's (after the host SCSI ID and
 394     geometry location are verified). */
 395 };
 396 
 397 #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
 398 
 399 static void print_banner( struct Scsi_Host *shpnt )
 400 {
 401    if (!shpnt) return;          /* This won't ever happen */
 402    
 403    printk( "scsi%d <fdomain>: BIOS version ", shpnt->host_no );
 404 
 405    if (bios_major >= 0) printk( "%d.", bios_major );
 406    else                 printk( "?." );
 407 
 408    if (bios_minor >= 0) printk( "%d", bios_minor );
 409    else                 printk( "?." );
 410    
 411    printk( " at 0x%x using scsi id %d\n",
 412            (unsigned)bios_base, shpnt->this_id );
 413 
 414    printk( "scsi%d <fdomain>: %s chip at 0x%x irq ",
 415            shpnt->host_no,
 416            chip == tmc1800 ? "TMC-1800"
 417            : (chip == tmc18c50 ? "TMC-18C50"
 418               : (chip == tmc18c30 ? "TMC-18C30" : "Unknown")),
 419            port_base );
 420 
 421    if (interrupt_level) printk( "%d", interrupt_level );
 422    else                 printk( "<none>" );
 423 
 424    if (PCI_bus)         printk( " (PCI bus)" );
 425    printk( "\n" );
 426 }
 427 
 428 static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
     /* [previous][next][first][last][top][bottom][index][help] */
 429 {
 430    unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
 431 
 432    while (jiffies < the_time);
 433 }
 434 
 435 inline static void fdomain_make_bus_idle( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437    outb( 0, SCSI_Cntl_port );
 438    outb( 0, SCSI_Mode_Cntl_port );
 439    if (chip == tmc18c50 || chip == tmc18c30)
 440          outb( 0x21 | PARITY_MASK, TMC_Cntl_port ); /* Clear forced intr. */
 441    else
 442          outb( 0x01 | PARITY_MASK, TMC_Cntl_port );
 443 }
 444 
 445 static int fdomain_is_valid_port( int port )
     /* [previous][next][first][last][top][bottom][index][help] */
 446 {
 447    int options;
 448 
 449 #if DEBUG_DETECT 
 450    printk( " (%x%x),",
 451            inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );
 452 #endif
 453 
 454    /* The MCA ID is a unique id for each MCA compatible board.  We
 455       are using ISA boards, but Future Domain provides the MCA ID
 456       anyway.  We can use this ID to ensure that this is a Future
 457       Domain TMC-1660/TMC-1680.
 458     */
 459 
 460    if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */
 461       if (inb( port + LSB_ID_Code ) != 0x27) return 0;
 462       if (inb( port + MSB_ID_Code ) != 0x61) return 0;
 463       chip = tmc1800;
 464    } else {                                 /* test for 0xe960 id */
 465       if (inb( port + MSB_ID_Code ) != 0x60) return 0;
 466       chip = tmc18c50;
 467 
 468 #if 0
 469 
 470                                 /* Try to toggle 32-bit mode.  This only
 471                                    works on an 18c30 chip.  (User reports
 472                                    say that this doesn't work at all, so
 473                                    we'll use the other method.) */
 474 
 475       outb( 0x80, port + IO_Control );
 476       if (inb( port + Configuration2 ) & 0x80 == 0x80) {
 477          outb( 0x00, port + IO_Control );
 478          if (inb( port + Configuration2 ) & 0x80 == 0x00) {
 479             chip = tmc18c30;
 480             FIFO_Size = 0x800;  /* 2k FIFO */
 481          }
 482       }
 483 #else
 484 
 485                                 /* That should have worked, but appears to
 486                                    have problems.  Lets assume it is an
 487                                    18c30 if the RAM is disabled. */
 488 
 489       if (inb( port + Configuration2 ) & 0x02) {
 490          chip      = tmc18c30;
 491          FIFO_Size = 0x800;     /* 2k FIFO */
 492       }
 493 #endif
 494                                 /* If that failed, we are an 18c50. */
 495    }
 496 
 497    /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board.
 498       Now, check to be sure the bios_base matches these ports.  If someone
 499       was unlucky enough to have purchased more than one Future Domain
 500       board, then they will have to modify this code, as we only detect one
 501       board here.  [The one with the lowest bios_base.]  */
 502 
 503    options = inb( port + Configuration1 );
 504 
 505 #if DEBUG_DETECT
 506    printk( " Options = %x\n", options );
 507 #endif
 508 
 509                                 /* Check for board with lowest bios_base --
 510                                    this isn't valid for the 18c30 or for
 511                                    boards on the PCI bus, so just assume we
 512                                    have the right board. */
 513 
 514    if (chip != tmc18c30
 515        && !PCI_bus
 516        && addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
 517 
 518                                 /* Get the IRQ from the options. */
 519 
 520    interrupt_level = ints[ (options & 0x0e) >> 1 ];
 521 
 522    return 1;
 523 }
 524 
 525 static int fdomain_test_loopback( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 526 {
 527    int i;
 528    int result;
 529 
 530    for (i = 0; i < 255; i++) {
 531       outb( i, port_base + Write_Loopback );
 532       result = inb( port_base + Read_Loopback );
 533       if (i != result)
 534             return 1;
 535    }
 536    return 0;
 537 }
 538 
 539 int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
     /* [previous][next][first][last][top][bottom][index][help] */
 540 {
 541    int              i, j;
 542    int              flag = 0;
 543    int              retcode;
 544    struct Scsi_Host *shpnt;
 545 #if DO_DETECT
 546    const int        buflen = 255;
 547    Scsi_Cmnd        SCinit;
 548    unsigned char    do_inquiry[] =       { INQUIRY, 0, 0, 0, buflen, 0 };
 549    unsigned char    do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 };
 550    unsigned char    do_read_capacity[] = { READ_CAPACITY,
 551                                            0, 0, 0, 0, 0, 0, 0, 0, 0 };
 552    unsigned char    buf[buflen];
 553 #endif
 554 
 555 #if DEBUG_DETECT
 556    printk( "fdomain_16x0_detect()," );
 557 #endif
 558 
 559    for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
 560 #if DEBUG_DETECT
 561       printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base );
 562 #endif
 563       for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) {
 564          if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset),
 565                       signatures[j].signature, signatures[j].sig_length )) {
 566             bios_major = signatures[j].major_bios_version;
 567             bios_minor = signatures[j].minor_bios_version;
 568             PCI_bus    = (signatures[j].flag == 1);
 569             Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;
 570             bios_base  = addresses[i];
 571          }
 572       }
 573    }
 574 
 575    if (!bios_base) {
 576 #if DEBUG_DETECT
 577       printk( " FAILED: NO BIOS\n" );
 578 #endif
 579       return 0;
 580    }
 581 
 582    if (bios_major == 2) {
 583       /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
 584          Assuming the ROM is enabled (otherwise we wouldn't have been
 585          able to read the ROM signature :-), then the ROM sets up the
 586          RAM area with some magic numbers, such as a list of port
 587          base addresses and a list of the disk "geometry" reported to
 588          DOS (this geometry has nothing to do with physical geometry).
 589        */
 590 
 591       switch (Quantum) {
 592       case 2:                   /* ISA_200S */
 593       case 3:                   /* ISA_250MG */
 594          port_base = *((char *)bios_base + 0x1fa2)
 595                + (*((char *)bios_base + 0x1fa3) << 8);
 596          break;
 597       case 4:                   /* ISA_200S (another one) */
 598          port_base = *((char *)bios_base + 0x1fa3)
 599                + (*((char *)bios_base + 0x1fa4) << 8);
 600          break;
 601       default:
 602          port_base = *((char *)bios_base + 0x1fcc)
 603                + (*((char *)bios_base + 0x1fcd) << 8);
 604          break;
 605       }
 606    
 607 #if DEBUG_DETECT
 608       printk( " %x,", port_base );
 609 #endif
 610 
 611       for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) {
 612          if (port_base == ports[i])
 613                ++flag;
 614       }
 615 
 616       if (flag)
 617             flag = fdomain_is_valid_port( port_base );
 618    }
 619 
 620    if (!flag) {                 /* Cannot get port base from BIOS RAM */
 621       
 622       /* This is a bad sign.  It usually means that someone patched the
 623          BIOS signature list (the signatures variable) to contain a BIOS
 624          signature for a board *OTHER THAN* the TMC-1660/TMC-1680.  It
 625          also means that we don't have a Version 2.0 BIOS :-)
 626        */
 627       
 628 #if DEBUG_DETECT
 629       if (bios_major != 2) printk( " RAM FAILED, " );
 630 #endif
 631 
 632       /* Anyway, the alternative to finding the address in the RAM is to
 633          just search through every possible port address for one that is
 634          attached to the Future Domain card.  Don't panic, though, about
 635          reading all these random port addresses -- there are rumors that
 636          the Future Domain BIOS does something very similar.
 637 
 638          Do not, however, check ports which the kernel knows are being used
 639          by another driver. */
 640 
 641       if (!PCI_bus) {
 642          for (i = 0; !flag && i < PORT_COUNT; i++) {
 643             port_base = ports[i];
 644             if (check_region( port_base, 0x10 )) {
 645 #if DEBUG_DETECT
 646                printk( " (%x inuse),", port_base );
 647 #endif
 648                continue;
 649             }
 650 #if DEBUG_DETECT
 651             printk( " %x,", port_base );
 652 #endif
 653             flag = fdomain_is_valid_port( port_base );
 654          }
 655       } else {
 656 
 657          /* The proper way of doing this is to use ask the PCI bus for the
 658             device IRQ and interrupt level.
 659 
 660             Until the Linux kernel supports this sort of PCI bus query, we
 661             scan down a bunch of addresses (Future Domain tech support says
 662             we will probably find the address before we get to 0xf800).
 663             This works fine on some systems -- other systems may have to
 664             scan more addresses.  If you have to modify this section for
 665             your installation, please send mail to faith@cs.unc.edu. */
 666 
 667          for (i = 0xfff8; !flag && i > 0xe000; i -= 8) {
 668             port_base = i;
 669             if (check_region( port_base, 0x10 )) {
 670 #if DEBUG_DETECT
 671                printk( " (%x inuse)," , port_base );
 672 #endif
 673                continue;
 674             }
 675             flag = fdomain_is_valid_port( port_base );
 676          }
 677       }
 678    }
 679 
 680    if (!flag) {
 681 #if DEBUG_DETECT
 682       printk( " FAILED: NO PORT\n" );
 683 #endif
 684       return 0;         /* Cannot find valid set of ports */
 685    }
 686 
 687    SCSI_Mode_Cntl_port   = port_base + SCSI_Mode_Cntl;
 688    FIFO_Data_Count_port  = port_base + FIFO_Data_Count;
 689    Interrupt_Cntl_port   = port_base + Interrupt_Cntl;
 690    Interrupt_Status_port = port_base + Interrupt_Status;
 691    Read_FIFO_port        = port_base + Read_FIFO;
 692    Read_SCSI_Data_port   = port_base + Read_SCSI_Data;
 693    SCSI_Cntl_port        = port_base + SCSI_Cntl;
 694    SCSI_Data_NoACK_port  = port_base + SCSI_Data_NoACK;
 695    SCSI_Status_port      = port_base + SCSI_Status;
 696    TMC_Cntl_port         = port_base + TMC_Cntl;
 697    TMC_Status_port       = port_base + TMC_Status;
 698    Write_FIFO_port       = port_base + Write_FIFO;
 699    Write_SCSI_Data_port  = port_base + Write_SCSI_Data;
 700 
 701    fdomain_16x0_reset( NULL );
 702 
 703    if (fdomain_test_loopback()) {
 704 #if DEBUG_DETECT
 705       printk( "fdomain: LOOPBACK TEST FAILED, FAILING DETECT!\n" );
 706 #endif
 707       return 0;
 708    }
 709 
 710    if ((bios_major == 3 && bios_minor >= 2) || bios_major < 0) {
 711       adapter_mask = 0x80;
 712       tpnt->this_id = 7;
 713    }
 714 
 715                                 /* Print out a banner here in case we can't
 716                                    get resources.  */
 717 
 718    shpnt = scsi_register( tpnt, 0 );
 719    print_banner( shpnt );
 720 
 721                                 /* Log IRQ with kernel */   
 722    if (!interrupt_level) {
 723       panic( "fdomain: *NO* interrupt level selected!\n" );
 724    } else {
 725       /* Register the IRQ with the kernel */
 726 
 727       retcode = request_irq( interrupt_level,
 728                              fdomain_16x0_intr, SA_INTERRUPT, "fdomain" );
 729 
 730       if (retcode < 0) {
 731          if (retcode == -EINVAL) {
 732             printk( "fdomain: IRQ %d is bad!\n", interrupt_level );
 733             printk( "         This shouldn't happen!\n" );
 734             printk( "         Send mail to faith@cs.unc.edu\n" );
 735          } else if (retcode == -EBUSY) {
 736             printk( "fdomain: IRQ %d is already in use!\n", interrupt_level );
 737             printk( "         Please use another IRQ!\n" );
 738          } else {
 739             printk( "fdomain: Error getting IRQ %d\n", interrupt_level );
 740             printk( "         This shouldn't happen!\n" );
 741             printk( "         Send mail to faith@cs.unc.edu\n" );
 742          }
 743          panic( "fdomain: Driver requires interruptions\n" );
 744       }
 745    }
 746 
 747                                 /* Log I/O ports with kernel */
 748    request_region( port_base, 0x10, "fdomain" );
 749 
 750 #if DO_DETECT
 751 
 752    /* These routines are here because of the way the SCSI bus behaves after
 753       a reset.  This appropriate behavior was not handled correctly by the
 754       higher level SCSI routines when I first wrote this driver.  Now,
 755       however, correct scan routines are part of scsi.c and these routines
 756       are no longer needed.  However, this code is still good for
 757       debugging.  */
 758 
 759    SCinit.request_buffer  = SCinit.buffer = buf;
 760    SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1;
 761    SCinit.use_sg          = 0;
 762    SCinit.lun             = 0;
 763 
 764    printk( "fdomain: detection routine scanning for devices:\n" );
 765    for (i = 0; i < 8; i++) {
 766       SCinit.target = i;
 767       if (i == tpnt->this_id)   /* Skip host adapter */
 768             continue;
 769       memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));
 770       retcode = fdomain_16x0_command(&SCinit);
 771       if (!retcode) {
 772          memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry));
 773          retcode = fdomain_16x0_command(&SCinit);
 774          if (!retcode) {
 775             printk( "     SCSI ID %d: ", i );
 776             for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++)
 777                   printk( "%c", buf[j] >= 20 ? buf[j] : ' ' );
 778             memcpy(SCinit.cmnd, do_read_capacity, sizeof(do_read_capacity));
 779             retcode = fdomain_16x0_command(&SCinit);
 780             if (!retcode) {
 781                unsigned long blocks, size, capacity;
 782                
 783                blocks = (buf[0] << 24) | (buf[1] << 16)
 784                      | (buf[2] << 8) | buf[3];
 785                size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
 786                capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L;
 787                
 788                printk( "%lu MB (%lu byte blocks)",
 789                        ((capacity + 5L) / 10L), size );
 790             } else {
 791                memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));
 792                retcode = fdomain_16x0_command(&SCinit);
 793             }
 794             printk ("\n" );
 795          } else {
 796             memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense));
 797             retcode = fdomain_16x0_command(&SCinit);
 798          }
 799       }
 800    }
 801 #endif
 802 
 803    return 1;                    /* Maximum of one adapter will be detected. */
 804 }
 805 
 806 const char *fdomain_16x0_info( struct Scsi_Host *ignore )
     /* [previous][next][first][last][top][bottom][index][help] */
 807 {
 808    static char buffer[80];
 809    char        *pt;
 810    
 811    strcpy( buffer, "Future Domain TMC-16x0 SCSI driver, version" );
 812    if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */
 813       strcat( buffer, strchr( VERSION, ':' ) + 1 );
 814       pt = strrchr( buffer, '$') - 1;
 815       if (!pt)                  /* Stripped RCS Revision string? */
 816             pt = buffer + strlen( buffer ) - 1;
 817       if (*pt != ' ')
 818             ++pt;
 819       *pt = '\0';
 820    } else {                     /* Assume VERSION is a number */
 821       strcat( buffer, " " VERSION );
 822    }
 823       
 824    return buffer;
 825 }
 826 
 827 #if 0
 828 static int fdomain_arbitrate( void )
     /* [previous][next][first][last][top][bottom][index][help] */
 829 {
 830    int           status = 0;
 831    unsigned long timeout;
 832 
 833 #if EVERY_ACCESS
 834    printk( "fdomain_arbitrate()\n" );
 835 #endif
 836    
 837    outb( 0x00, SCSI_Cntl_port );              /* Disable data drivers */
 838    outb( adapter_mask, port_base + SCSI_Data_NoACK ); /* Set our id bit */
 839    outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
 840 
 841    timeout = jiffies + 50;                    /* 500 mS */
 842    while (jiffies < timeout) {
 843       status = inb( TMC_Status_port );        /* Read adapter status */
 844       if (status & 0x02)                      /* Arbitration complete */
 845             return 0;   
 846    }
 847 
 848    /* Make bus idle */
 849    fdomain_make_bus_idle();
 850 
 851 #if EVERY_ACCESS
 852    printk( "Arbitration failed, status = %x\n", status );
 853 #endif
 854 #if ERRORS_ONLY
 855    printk( "fdomain: Arbitration failed, status = %x\n", status );
 856 #endif
 857    return 1;
 858 }
 859 #endif
 860 
 861 static int fdomain_select( int target )
     /* [previous][next][first][last][top][bottom][index][help] */
 862 {
 863    int           status;
 864    unsigned long timeout;
 865    static int    flag = 0;
 866 
 867 
 868    outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
 869    outb( adapter_mask | (1 << target), SCSI_Data_NoACK_port );
 870 
 871    /* Stop arbitration and enable parity */
 872    outb( PARITY_MASK, TMC_Cntl_port ); 
 873 
 874    timeout = jiffies + 35;              /* 350mS -- because of timeouts
 875                                            (was 250mS) */
 876 
 877    while (jiffies < timeout) {
 878       status = inb( SCSI_Status_port ); /* Read adapter status */
 879       if (status & 1) {                 /* Busy asserted */
 880          /* Enable SCSI Bus (on error, should make bus idle with 0) */
 881          outb( 0x80, SCSI_Cntl_port );
 882          return 0;
 883       }
 884    }
 885    /* Make bus idle */
 886    fdomain_make_bus_idle();
 887 #if EVERY_ACCESS
 888    if (!target) printk( "Selection failed\n" );
 889 #endif
 890 #if ERRORS_ONLY
 891    if (!target) {
 892       if (chip == tmc18c30 && !flag) /* Skip first failure for 18C30 chips. */
 893             ++flag;
 894       else
 895             printk( "fdomain: Selection failed\n" );
 896    }
 897 #endif
 898    return 1;
 899 }
 900 
 901 void my_done( int error )
     /* [previous][next][first][last][top][bottom][index][help] */
 902 {
 903    if (in_command) {
 904       in_command = 0;
 905       outb( 0x00, Interrupt_Cntl_port );
 906       fdomain_make_bus_idle();
 907       current_SC->result = error;
 908       if (current_SC->scsi_done)
 909             current_SC->scsi_done( current_SC );
 910       else panic( "fdomain: current_SC->scsi_done() == NULL" );
 911    } else {
 912       panic( "fdomain: my_done() called outside of command\n" );
 913    }
 914 #if DEBUG_RACE
 915    in_interrupt_flag = 0;
 916 #endif
 917 }
 918 
 919 void fdomain_16x0_intr( int irq, struct pt_regs * regs )
     /* [previous][next][first][last][top][bottom][index][help] */
 920 {
 921    int      status;
 922    int      done = 0;
 923    unsigned data_count;
 924 
 925                                 /* The fdomain_16x0_intr is only called via
 926                                    the interrupt handler.  The goal of the
 927                                    sti() here is to allow other
 928                                    interruptions while this routine is
 929                                    running. */
 930 
 931    sti();                       /* Yes, we really want sti() here */
 932    
 933    outb( 0x00, Interrupt_Cntl_port );
 934 
 935    /* We usually have one spurious interrupt after each command.  Ignore it. */
 936    if (!in_command || !current_SC) {    /* Spurious interrupt */
 937 #if EVERY_ACCESS
 938       printk( "Spurious interrupt, in_command = %d, current_SC = %x\n",
 939               in_command, current_SC );
 940 #endif
 941       return;
 942    }
 943 
 944    /* Abort calls my_done, so we do nothing here. */
 945    if (current_SC->SCp.phase & aborted) {
 946 #if DEBUG_ABORT
 947       printk( "Interrupt after abort, ignoring\n" );
 948 #endif
 949       /*
 950       return; */
 951    }
 952 
 953 #if DEBUG_RACE
 954    ++in_interrupt_flag;
 955 #endif
 956 
 957    if (current_SC->SCp.phase & in_arbitration) {
 958       status = inb( TMC_Status_port );        /* Read adapter status */
 959       if (!(status & 0x02)) {
 960 #if EVERY_ACCESS
 961          printk( " AFAIL " );
 962 #endif
 963          my_done( DID_BUS_BUSY << 16 );
 964          return;
 965       }
 966       current_SC->SCp.phase = in_selection;
 967       
 968       outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port );
 969 
 970       outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
 971       outb( adapter_mask | (1 << current_SC->target), SCSI_Data_NoACK_port );
 972       
 973       /* Stop arbitration and enable parity */
 974       outb( 0x10 | PARITY_MASK, TMC_Cntl_port );
 975 #if DEBUG_RACE
 976       in_interrupt_flag = 0;
 977 #endif
 978       return;
 979    } else if (current_SC->SCp.phase & in_selection) {
 980       status = inb( SCSI_Status_port );
 981       if (!(status & 0x01)) {
 982          /* Try again, for slow devices */
 983          if (fdomain_select( current_SC->target )) {
 984 #if EVERY_ACCESS
 985             printk( " SFAIL " );
 986 #endif
 987             my_done( DID_NO_CONNECT << 16 );
 988             return;
 989          } else {
 990 #if EVERY_ACCESS
 991             printk( " AltSel " );
 992 #endif
 993             /* Stop arbitration and enable parity */
 994             outb( 0x10 | PARITY_MASK, TMC_Cntl_port );
 995          }
 996       }
 997       current_SC->SCp.phase = in_other;
 998       outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
 999       outb( 0x80, SCSI_Cntl_port );
1000 #if DEBUG_RACE
1001       in_interrupt_flag = 0;
1002 #endif
1003       return;
1004    }
1005    
1006    /* current_SC->SCp.phase == in_other: this is the body of the routine */
1007    
1008    status = inb( SCSI_Status_port );
1009    
1010    if (status & 0x10) { /* REQ */
1011       
1012       switch (status & 0x0e) {
1013        
1014       case 0x08:                /* COMMAND OUT */
1015          outb( current_SC->cmnd[current_SC->SCp.sent_command++],
1016                Write_SCSI_Data_port );
1017 #if EVERY_ACCESS
1018          printk( "CMD = %x,",
1019                  current_SC->cmnd[ current_SC->SCp.sent_command - 1] );
1020 #endif
1021          break;
1022       case 0x00:                /* DATA OUT -- tmc18c50/tmc18c30 only */
1023          if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
1024             current_SC->SCp.have_data_in = -1;
1025             outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
1026          }
1027          break;
1028       case 0x04:                /* DATA IN -- tmc18c50/tmc18c30 only */
1029          if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
1030             current_SC->SCp.have_data_in = 1;
1031             outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
1032          }
1033          break;
1034       case 0x0c:                /* STATUS IN */
1035          current_SC->SCp.Status = inb( Read_SCSI_Data_port );
1036 #if EVERY_ACCESS
1037          printk( "Status = %x, ", current_SC->SCp.Status );
1038 #endif
1039 #if ERRORS_ONLY
1040          if (current_SC->SCp.Status && current_SC->SCp.Status != 2) {
1041             printk( "fdomain: target = %d, command = %x, status = %x\n",
1042                     current_SC->target,
1043                     current_SC->cmnd[0],
1044                     current_SC->SCp.Status );
1045          }
1046 #endif
1047                break;
1048       case 0x0a:                /* MESSAGE OUT */
1049          outb( MESSAGE_REJECT, Write_SCSI_Data_port ); /* Reject */
1050          break;
1051       case 0x0e:                /* MESSAGE IN */
1052          current_SC->SCp.Message = inb( Read_SCSI_Data_port );
1053 #if EVERY_ACCESS
1054          printk( "Message = %x, ", current_SC->SCp.Message );
1055 #endif
1056          if (!current_SC->SCp.Message) ++done;
1057 #if DEBUG_MESSAGES || EVERY_ACCESS
1058          if (current_SC->SCp.Message) {
1059             printk( "fdomain: message = %x\n", current_SC->SCp.Message );
1060          }
1061 #endif
1062          break;
1063       }
1064    }
1065 
1066    if (chip == tmc1800
1067        && !current_SC->SCp.have_data_in
1068        && (current_SC->SCp.sent_command
1069            >= current_SC->cmd_len)) {
1070                                 /* We have to get the FIFO direction
1071                                    correct, so I've made a table based
1072                                    on the SCSI Standard of which commands
1073                                    appear to require a DATA OUT phase.
1074                                  */
1075       /*
1076         p. 94: Command for all device types
1077         CHANGE DEFINITION            40 DATA OUT
1078         COMPARE                      39 DATA OUT
1079         COPY                         18 DATA OUT
1080         COPY AND VERIFY              3a DATA OUT
1081         INQUIRY                      12 
1082         LOG SELECT                   4c DATA OUT
1083         LOG SENSE                    4d
1084         MODE SELECT (6)              15 DATA OUT
1085         MODE SELECT (10)             55 DATA OUT
1086         MODE SENSE (6)               1a
1087         MODE SENSE (10)              5a
1088         READ BUFFER                  3c
1089         RECEIVE DIAGNOSTIC RESULTS   1c
1090         REQUEST SENSE                03
1091         SEND DIAGNOSTIC              1d DATA OUT
1092         TEST UNIT READY              00
1093         WRITE BUFFER                 3b DATA OUT
1094 
1095         p.178: Commands for direct-access devices (not listed on p. 94)
1096         FORMAT UNIT                  04 DATA OUT
1097         LOCK-UNLOCK CACHE            36
1098         PRE-FETCH                    34
1099         PREVENT-ALLOW MEDIUM REMOVAL 1e
1100         READ (6)/RECEIVE             08
1101         READ (10)                    3c
1102         READ CAPACITY                25
1103         READ DEFECT DATA (10)        37
1104         READ LONG                    3e
1105         REASSIGN BLOCKS              07 DATA OUT
1106         RELEASE                      17
1107         RESERVE                      16 DATA OUT
1108         REZERO UNIT/REWIND           01
1109         SEARCH DATA EQUAL (10)       31 DATA OUT
1110         SEARCH DATA HIGH (10)        30 DATA OUT
1111         SEARCH DATA LOW (10)         32 DATA OUT
1112         SEEK (6)                     0b
1113         SEEK (10)                    2b
1114         SET LIMITS (10)              33
1115         START STOP UNIT              1b
1116         SYNCHRONIZE CACHE            35
1117         VERIFY (10)                  2f
1118         WRITE (6)/PRINT/SEND         0a DATA OUT
1119         WRITE (10)/SEND              2a DATA OUT
1120         WRITE AND VERIFY (10)        2e DATA OUT
1121         WRITE LONG                   3f DATA OUT
1122         WRITE SAME                   41 DATA OUT ?
1123 
1124         p. 261: Commands for sequential-access devices (not previously listed)
1125         ERASE                        19
1126         LOAD UNLOAD                  1b
1127         LOCATE                       2b
1128         READ BLOCK LIMITS            05
1129         READ POSITION                34
1130         READ REVERSE                 0f
1131         RECOVER BUFFERED DATA        14
1132         SPACE                        11
1133         WRITE FILEMARKS              10 ?
1134 
1135         p. 298: Commands for printer devices (not previously listed)
1136         ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
1137         SLEW AND PRINT               0b DATA OUT  -- same as seek
1138         STOP PRINT                   1b
1139         SYNCHRONIZE BUFFER           10
1140 
1141         p. 315: Commands for processor devices (not previously listed)
1142         
1143         p. 321: Commands for write-once devices (not previously listed)
1144         MEDIUM SCAN                  38
1145         READ (12)                    a8
1146         SEARCH DATA EQUAL (12)       b1 DATA OUT
1147         SEARCH DATA HIGH (12)        b0 DATA OUT
1148         SEARCH DATA LOW (12)         b2 DATA OUT
1149         SET LIMITS (12)              b3
1150         VERIFY (12)                  af
1151         WRITE (12)                   aa DATA OUT
1152         WRITE AND VERIFY (12)        ae DATA OUT
1153 
1154         p. 332: Commands for CD-ROM devices (not previously listed)
1155         PAUSE/RESUME                 4b
1156         PLAY AUDIO (10)              45
1157         PLAY AUDIO (12)              a5
1158         PLAY AUDIO MSF               47
1159         PLAY TRACK RELATIVE (10)     49
1160         PLAY TRACK RELATIVE (12)     a9
1161         READ HEADER                  44
1162         READ SUB-CHANNEL             42
1163         READ TOC                     43
1164 
1165         p. 370: Commands for scanner devices (not previously listed)
1166         GET DATA BUFFER STATUS       34
1167         GET WINDOW                   25
1168         OBJECT POSITION              31
1169         SCAN                         1b
1170         SET WINDOW                   24 DATA OUT
1171 
1172         p. 391: Commands for optical memory devices (not listed)
1173         ERASE (10)                   2c
1174         ERASE (12)                   ac
1175         MEDIUM SCAN                  38 DATA OUT
1176         READ DEFECT DATA (12)        b7
1177         READ GENERATION              29
1178         READ UPDATED BLOCK           2d
1179         UPDATE BLOCK                 3d DATA OUT
1180 
1181         p. 419: Commands for medium changer devices (not listed)
1182         EXCHANGE MEDIUM              46
1183         INITIALIZE ELEMENT STATUS    07
1184         MOVE MEDIUM                  a5
1185         POSITION TO ELEMENT          2b
1186         READ ELEMENT STATUS          b8
1187         REQUEST VOL. ELEMENT ADDRESS b5
1188         SEND VOLUME TAG              b6 DATA OUT
1189 
1190         p. 454: Commands for communications devices (not listed previously)
1191         GET MESSAGE (6)              08
1192         GET MESSAGE (10)             28
1193         GET MESSAGE (12)             a8
1194       */
1195         
1196       switch (current_SC->cmnd[0]) {
1197       case CHANGE_DEFINITION: case COMPARE:         case COPY:
1198       case COPY_VERIFY:       case LOG_SELECT:      case MODE_SELECT:
1199       case MODE_SELECT_10:    case SEND_DIAGNOSTIC: case WRITE_BUFFER:
1200 
1201       case FORMAT_UNIT:       case REASSIGN_BLOCKS: case RESERVE:
1202       case SEARCH_EQUAL:      case SEARCH_HIGH:     case SEARCH_LOW:
1203       case WRITE_6:           case WRITE_10:        case WRITE_VERIFY:
1204       case 0x3f:              case 0x41:
1205 
1206       case 0xb1:              case 0xb0:            case 0xb2:
1207       case 0xaa:              case 0xae:
1208 
1209       case 0x24:
1210 
1211       case 0x38:              case 0x3d:
1212 
1213       case 0xb6:
1214          
1215       case 0xea:                /* alternate number for WRITE LONG */
1216          
1217          current_SC->SCp.have_data_in = -1;
1218          outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
1219          break;
1220 
1221       case 0x00:
1222       default:
1223          
1224          current_SC->SCp.have_data_in = 1;
1225          outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
1226          break;
1227       }
1228    }
1229 
1230    if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */
1231       while ( (data_count = FIFO_Size - inw( FIFO_Data_Count_port )) > 512 ) {
1232 #if EVERY_ACCESS
1233          printk( "DC=%d, ", data_count ) ;
1234 #endif
1235          if (data_count > current_SC->SCp.this_residual)
1236                data_count = current_SC->SCp.this_residual;
1237          if (data_count > 0) {
1238 #if EVERY_ACCESS
1239             printk( "%d OUT, ", data_count );
1240 #endif
1241             if (data_count == 1) {
1242                outb( *current_SC->SCp.ptr++, Write_FIFO_port );
1243                --current_SC->SCp.this_residual;
1244             } else {
1245                data_count >>= 1;
1246                outsw( Write_FIFO_port, current_SC->SCp.ptr, data_count );
1247                current_SC->SCp.ptr += 2 * data_count;
1248                current_SC->SCp.this_residual -= 2 * data_count;
1249             }
1250          }
1251          if (!current_SC->SCp.this_residual) {
1252             if (current_SC->SCp.buffers_residual) {
1253                --current_SC->SCp.buffers_residual;
1254                ++current_SC->SCp.buffer;
1255                current_SC->SCp.ptr = current_SC->SCp.buffer->address;
1256                current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
1257             } else
1258                   break;
1259          }
1260       }
1261    }
1262    
1263    if (current_SC->SCp.have_data_in == 1) { /* DATA IN */
1264       while ((data_count = inw( FIFO_Data_Count_port )) > 0) {
1265 #if EVERY_ACCESS
1266          printk( "DC=%d, ", data_count );
1267 #endif
1268          if (data_count > current_SC->SCp.this_residual)
1269                data_count = current_SC->SCp.this_residual;
1270          if (data_count) {
1271 #if EVERY_ACCESS
1272             printk( "%d IN, ", data_count );
1273 #endif
1274             if (data_count == 1) {
1275                *current_SC->SCp.ptr++ = inb( Read_FIFO_port );
1276                --current_SC->SCp.this_residual;
1277             } else {
1278                data_count >>= 1; /* Number of words */
1279                insw( Read_FIFO_port, current_SC->SCp.ptr, data_count );
1280                current_SC->SCp.ptr += 2 * data_count;
1281                current_SC->SCp.this_residual -= 2 * data_count;
1282             }
1283          }
1284          if (!current_SC->SCp.this_residual
1285              && current_SC->SCp.buffers_residual) {
1286             --current_SC->SCp.buffers_residual;
1287             ++current_SC->SCp.buffer;
1288             current_SC->SCp.ptr = current_SC->SCp.buffer->address;
1289             current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
1290          }
1291       }
1292    }
1293    
1294    if (done) {
1295 #if EVERY_ACCESS
1296       printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in );
1297 #endif
1298 
1299 #if ERRORS_ONLY
1300       if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
1301          if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) {
1302             unsigned char key;
1303             unsigned char code;
1304             unsigned char qualifier;
1305 
1306             key = (unsigned char)(*((char *)current_SC->request_buffer + 2))
1307                   & 0x0f;
1308             code = (unsigned char)(*((char *)current_SC->request_buffer + 12));
1309             qualifier = (unsigned char)(*((char *)current_SC->request_buffer
1310                                           + 13));
1311 
1312             if (!(key == UNIT_ATTENTION && (code == 0x29 || !code))
1313                 && !(key == NOT_READY
1314                      && code == 0x04
1315                      && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
1316                 && !(key == ILLEGAL_REQUEST && (code == 0x25
1317                                                 || code == 0x24
1318                                                 || !code)))
1319                   
1320                   printk( "fdomain: REQUEST SENSE "
1321                           "Key = %x, Code = %x, Qualifier = %x\n",
1322                           key, code, qualifier );
1323          }
1324       }
1325 #endif
1326 #if EVERY_ACCESS
1327       printk( "BEFORE MY_DONE. . ." );
1328 #endif
1329       my_done( (current_SC->SCp.Status & 0xff)
1330                | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
1331 #if EVERY_ACCESS
1332       printk( "RETURNING.\n" );
1333 #endif
1334       
1335    } else {
1336       if (current_SC->SCp.phase & disconnect) {
1337          outb( 0xd0 | FIFO_COUNT, Interrupt_Cntl_port );
1338          outb( 0x00, SCSI_Cntl_port );
1339       } else {
1340          outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
1341       }
1342    }
1343 #if DEBUG_RACE
1344    in_interrupt_flag = 0;
1345 #endif
1346    return;
1347 }
1348 
1349 int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
1350 {
1351    if (in_command) {
1352       panic( "fdomain: fdomain_16x0_queue() NOT REENTRANT!\n" );
1353    }
1354 #if EVERY_ACCESS
1355    printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
1356            SCpnt->target,
1357            *(unsigned char *)SCpnt->cmnd,
1358            SCpnt->use_sg,
1359            SCpnt->request_bufflen );
1360 #endif
1361 
1362    fdomain_make_bus_idle();
1363 
1364    current_SC            = SCpnt; /* Save this for the done function */
1365    current_SC->scsi_done = done;
1366 
1367    /* Initialize static data */
1368 
1369    if (current_SC->use_sg) {
1370       current_SC->SCp.buffer =
1371             (struct scatterlist *)current_SC->request_buffer;
1372       current_SC->SCp.ptr              = current_SC->SCp.buffer->address;
1373       current_SC->SCp.this_residual    = current_SC->SCp.buffer->length;
1374       current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
1375    } else {
1376       current_SC->SCp.ptr              = (char *)current_SC->request_buffer;
1377       current_SC->SCp.this_residual    = current_SC->request_bufflen;
1378       current_SC->SCp.buffer           = NULL;
1379       current_SC->SCp.buffers_residual = 0;
1380    }
1381          
1382    
1383    current_SC->SCp.Status              = 0;
1384    current_SC->SCp.Message             = 0;
1385    current_SC->SCp.have_data_in        = 0;
1386    current_SC->SCp.sent_command        = 0;
1387    current_SC->SCp.phase               = in_arbitration;
1388 
1389    /* Start arbitration */
1390    outb( 0x00, Interrupt_Cntl_port );
1391    outb( 0x00, SCSI_Cntl_port );              /* Disable data drivers */
1392    outb( adapter_mask, SCSI_Data_NoACK_port ); /* Set our id bit */
1393    ++in_command;
1394    outb( 0x20, Interrupt_Cntl_port );
1395    outb( 0x14 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
1396 
1397    return 0;
1398 }
1399 
1400 /* The following code, which simulates the old-style command function, was
1401    taken from Tommy Thorn's aha1542.c file.  This code is Copyright (C)
1402    1992 Tommy Thorn. */
1403 
1404 static volatile int internal_done_flag    = 0;
1405 static volatile int internal_done_errcode = 0;
1406 
1407 static void internal_done( Scsi_Cmnd *SCpnt )
     /* [previous][next][first][last][top][bottom][index][help] */
1408 {
1409     internal_done_errcode = SCpnt->result;
1410     ++internal_done_flag;
1411 }
1412 
1413 int fdomain_16x0_command( Scsi_Cmnd *SCpnt )
     /* [previous][next][first][last][top][bottom][index][help] */
1414 {
1415     fdomain_16x0_queue( SCpnt, internal_done );
1416 
1417     while (!internal_done_flag)
1418           ;
1419     internal_done_flag = 0;
1420     return internal_done_errcode;
1421 }
1422 
1423 /* End of code derived from Tommy Thorn's work. */
1424 
1425 void print_info( Scsi_Cmnd *SCpnt )
     /* [previous][next][first][last][top][bottom][index][help] */
1426 {
1427    unsigned int imr;
1428    unsigned int irr;
1429    unsigned int isr;
1430 
1431    if (!SCpnt || !SCpnt->host) {
1432       printk( "fdomain: cannot provide detailed information\n" );
1433    }
1434    
1435    printk( "%s\n", fdomain_16x0_info( SCpnt->host ) );
1436    print_banner( SCpnt->host );
1437    switch (SCpnt->SCp.phase) {
1438    case in_arbitration: printk( "arbitration " ); break;
1439    case in_selection:   printk( "selection " );   break;
1440    case in_other:       printk( "other " );       break;
1441    default:             printk( "unknown " );     break;
1442    }
1443 
1444    printk( "(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
1445            SCpnt->SCp.phase,
1446            SCpnt->target,
1447            *(unsigned char *)SCpnt->cmnd,
1448            SCpnt->use_sg,
1449            SCpnt->request_bufflen );
1450    printk( "sent_command = %d, have_data_in = %d, timeout = %d\n",
1451            SCpnt->SCp.sent_command,
1452            SCpnt->SCp.have_data_in,
1453            SCpnt->timeout );
1454 #if DEBUG_RACE
1455    printk( "in_interrupt_flag = %d\n", in_interrupt_flag );
1456 #endif
1457 
1458    imr = (inb( 0x0a1 ) << 8) + inb( 0x21 );
1459    outb( 0x0a, 0xa0 );
1460    irr = inb( 0xa0 ) << 8;
1461    outb( 0x0a, 0x20 );
1462    irr += inb( 0x20 );
1463    outb( 0x0b, 0xa0 );
1464    isr = inb( 0xa0 ) << 8;
1465    outb( 0x0b, 0x20 );
1466    isr += inb( 0x20 );
1467 
1468                                 /* Print out interesting information */
1469    printk( "IMR = 0x%04x", imr );
1470    if (imr & (1 << interrupt_level))
1471          printk( " (masked)" );
1472    printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr );
1473 
1474    printk( "SCSI Status      = 0x%02x\n", inb( SCSI_Status_port ) );
1475    printk( "TMC Status       = 0x%02x", inb( TMC_Status_port ) );
1476    if (inb( TMC_Status_port & 1))
1477          printk( " (interrupt)" );
1478    printk( "\n" );
1479    printk( "Interrupt Status = 0x%02x", inb( Interrupt_Status_port ) );
1480    if (inb( Interrupt_Status_port ) & 0x08)
1481          printk( " (enabled)" );
1482    printk( "\n" );
1483    if (chip == tmc18c50 || chip == tmc18c30) {
1484       printk( "FIFO Status      = 0x%02x\n", inb( port_base + FIFO_Status ) );
1485       printk( "Int. Condition   = 0x%02x\n",
1486               inb( port_base + Interrupt_Cond ) );
1487    }
1488    printk( "Configuration 1  = 0x%02x\n", inb( port_base + Configuration1 ) );
1489    if (chip == tmc18c50 || chip == tmc18c30)
1490          printk( "Configuration 2  = 0x%02x\n",
1491                  inb( port_base + Configuration2 ) );
1492 }
1493 
1494 int fdomain_16x0_abort( Scsi_Cmnd *SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
1495 {
1496    unsigned long flags;
1497 #if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
1498    printk( "fdomain: abort " );
1499 #endif
1500 
1501    save_flags( flags );
1502    cli();
1503    if (!in_command) {
1504 #if EVERY_ACCESS || ERRORS_ONLY
1505       printk( " (not in command)\n" );
1506 #endif
1507       restore_flags( flags );
1508       return SCSI_ABORT_NOT_RUNNING;
1509    }
1510 
1511 #if DEBUG_ABORT
1512    print_info( SCpnt );
1513 #endif
1514 
1515    fdomain_make_bus_idle();
1516 
1517    current_SC->SCp.phase |= aborted;
1518 
1519    current_SC->result = DID_ABORT << 16;
1520 
1521    restore_flags( flags );
1522    
1523    /* Aborts are not done well. . . */
1524    my_done( DID_ABORT << 16 );
1525 
1526    return SCSI_ABORT_SUCCESS;
1527 }
1528 
1529 int fdomain_16x0_reset( Scsi_Cmnd *SCpnt )
     /* [previous][next][first][last][top][bottom][index][help] */
1530 {
1531 #if DEBUG_RESET
1532    static int called_once = 0;
1533 #endif
1534 
1535 #if ERRORS_ONLY
1536    if (SCpnt) printk( "fdomain: SCSI Bus Reset\n" );
1537 #endif
1538 
1539 #if DEBUG_RESET
1540    if (called_once) print_info( current_SC );
1541    called_once = 1;
1542 #endif
1543    
1544    outb( 1, SCSI_Cntl_port );
1545    do_pause( 2 );
1546    outb( 0, SCSI_Cntl_port );
1547    do_pause( 115 );
1548    outb( 0, SCSI_Mode_Cntl_port );
1549    outb( PARITY_MASK, TMC_Cntl_port );
1550 
1551    /* Unless this is the very first call (i.e., SCPnt == NULL), everything
1552       is probably hosed at this point.  We will, however, try to keep
1553       things going by informing the high-level code that we need help. */
1554 
1555    return SCSI_RESET_WAKEUP;
1556 }
1557 
1558 #include "sd.h"
1559 #include "scsi_ioctl.h"
1560 
1561 int fdomain_16x0_biosparam( Scsi_Disk *disk, int dev, int *info_array )
     /* [previous][next][first][last][top][bottom][index][help] */
1562 {
1563    int              drive;
1564    unsigned char    buf[512 + sizeof( int ) * 2];
1565    int              size      = disk->capacity;
1566    int              *sizes    = (int *)buf;
1567    unsigned char    *data     = (unsigned char *)(sizes + 2);
1568    unsigned char    do_read[] = { READ_6, 0, 0, 0, 1, 0 };
1569    int              retcode;
1570    struct drive_info {
1571       unsigned short cylinders;
1572       unsigned char  heads;
1573       unsigned char  sectors;
1574    } *i;
1575    
1576    /* NOTES:
1577       The RAM area starts at 0x1f00 from the bios_base address.
1578 
1579       For BIOS Version 2.0:
1580       
1581       The drive parameter table seems to start at 0x1f30.
1582       The first byte's purpose is not known.
1583       Next is the cylinder, head, and sector information.
1584       The last 4 bytes appear to be the drive's size in sectors.
1585       The other bytes in the drive parameter table are unknown.
1586       If anyone figures them out, please send me mail, and I will
1587       update these notes.
1588 
1589       Tape drives do not get placed in this table.
1590 
1591       There is another table at 0x1fea:
1592       If the byte is 0x01, then the SCSI ID is not in use.
1593       If the byte is 0x18 or 0x48, then the SCSI ID is in use,
1594       although tapes don't seem to be in this table.  I haven't
1595       seen any other numbers (in a limited sample).
1596 
1597       0x1f2d is a drive count (i.e., not including tapes)
1598 
1599       The table at 0x1fcc are I/O ports addresses for the various
1600       operations.  I calculate these by hand in this driver code.
1601 
1602       
1603       
1604       For the ISA-200S version of BIOS Version 2.0:
1605 
1606       The drive parameter table starts at 0x1f33.
1607 
1608       WARNING: Assume that the table entry is 25 bytes long.  Someone needs
1609       to check this for the Quantum ISA-200S card.
1610 
1611       
1612       
1613       For BIOS Version 3.2:
1614 
1615       The drive parameter table starts at 0x1f70.  Each entry is
1616       0x0a bytes long.  Heads are one less than we need to report.
1617     */
1618 
1619    drive = MINOR(dev) / 16;
1620 
1621    if (bios_major == 2) {
1622       switch (Quantum) {
1623       case 2:                   /* ISA_200S */
1624                                 /* The value of 25 has never been verified.
1625                                    It should probably be 15. */
1626          i = (struct drive_info *)( (char *)bios_base + 0x1f33 + drive * 25 );
1627          break;
1628       case 3:                   /* ISA_250MG */
1629          i = (struct drive_info *)( (char *)bios_base + 0x1f36 + drive * 15 );
1630          break;
1631       case 4:                   /* ISA_200S (another one) */
1632          i = (struct drive_info *)( (char *)bios_base + 0x1f34 + drive * 15 );
1633          break;
1634       default:
1635          i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 );
1636          break;
1637       }
1638       info_array[0] = i->heads;
1639       info_array[1] = i->sectors;
1640       info_array[2] = i->cylinders;
1641    } else if (bios_major == 3
1642               && bios_minor >= 0
1643               && bios_minor < 4) { /* 3.0 and 3.2 BIOS */
1644       i = (struct drive_info *)( (char *)bios_base + 0x1f71 + drive * 10 );
1645       info_array[0] = i->heads + 1;
1646       info_array[1] = i->sectors;
1647       info_array[2] = i->cylinders;
1648    } else {                     /* 3.4 BIOS (and up?) */
1649       /* This algorithm was provided by Future Domain (much thanks!). */
1650 
1651       sizes[0] = 0;             /* zero bytes out */
1652       sizes[1] = 512;           /* one sector in */
1653       memcpy( data, do_read, sizeof( do_read ) );
1654       retcode = kernel_scsi_ioctl( disk->device,
1655                                    SCSI_IOCTL_SEND_COMMAND,
1656                                    (void *)buf );
1657       if (!retcode                                  /* SCSI command ok */
1658           && data[511] == 0xaa && data[510] == 0x55 /* Partition table valid */
1659           && data[0x1c2]) {                         /* Partition type */
1660 
1661          /* The partition table layout is as follows:
1662 
1663             Start: 0x1b3h
1664             Offset: 0 = partition status
1665                     1 = starting head
1666                     2 = starting sector and cylinder (word, encoded)
1667                     4 = partition type
1668                     5 = ending head
1669                     6 = ending sector and cylinder (word, encoded)
1670                     8 = starting absolute sector (double word)
1671                     c = number of sectors (double word)
1672             Signature: 0x1fe = 0x55aa
1673 
1674             So, this algorithm assumes:
1675             1) the first partition table is in use,
1676             2) the data in the first entry is correct, and
1677             3) partitions never divide cylinders
1678 
1679             Note that (1) may be FALSE for NetBSD (and other BSD flavors),
1680             as well as for Linux.  Note also, that Linux doesn't pay any
1681             attention to the fields that are used by this algorithm -- it
1682             only uses the absolute sector data.  Recent versions of Linux's
1683             fdisk(1) will fill this data in correctly, and forthcoming
1684             versions will check for consistency.
1685 
1686             Checking for a non-zero partition type is not part of the
1687             Future Domain algorithm, but it seemed to be a reasonable thing
1688             to do, especially in the Linux and BSD worlds. */
1689 
1690          info_array[0] = data[0x1c3] + 1;           /* heads */
1691          info_array[1] = data[0x1c4] & 0x3f;        /* sectors */
1692       } else {
1693 
1694          /* Note that this new method guarantees that there will always be
1695             less than 1024 cylinders on a platter.  This is good for drives
1696             up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
1697 
1698          if ((unsigned int)size >= 0x7e0000U) {
1699             info_array[0] = 0xff; /* heads   = 255 */
1700             info_array[1] = 0x3f; /* sectors =  63 */
1701          } else if ((unsigned int)size >= 0x200000U) {
1702             info_array[0] = 0x80; /* heads   = 128 */
1703             info_array[1] = 0x3f; /* sectors =  63 */
1704          } else {
1705             info_array[0] = 0x40; /* heads   =  64 */
1706             info_array[1] = 0x20; /* sectors =  32 */
1707          }
1708       }
1709                                 /* For both methods, compute the cylinders */
1710       info_array[2] = (unsigned int)size / (info_array[0] * info_array[1] );
1711    }
1712    
1713    return 0;
1714 }

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