root/drivers/scsi/pas16.c

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

DEFINITIONS

This source file includes following definitions.
  1. enable_board
  2. init_board
  3. pas16_hw_detect
  4. pas16_setup
  5. pas16_detect
  6. pas16_biosparam
  7. NCR5380_pread
  8. NCR5380_pwrite
  9. pas16_info

   1 #define AUTOSENSE
   2 #define PSEUDO_DMA
   3 
   4 /*
   5  * This driver adapted from Drew Eckhardt's Trantor T128 driver
   6  *
   7  * Copyright 1993, Drew Eckhardt
   8  *      Visionary Computing
   9  *      (Unix and Linux consulting and custom programming)
  10  *      drew@colorado.edu
  11  *      +1 (303) 666-5836
  12  *
  13  *  ( Based on T128 - DISTRIBUTION RELEASE 3. ) 
  14  *
  15  * Modified to work with the Pro Audio Spectrum/Studio 16
  16  * by John Weidman.
  17  *
  18  *
  19  * For more information, please consult 
  20  *
  21  * Media Vision
  22  * (510) 770-8600
  23  * (800) 348-7116
  24  * 
  25  * and 
  26  *
  27  * NCR 5380 Family
  28  * SCSI Protocol Controller
  29  * Databook
  30  *
  31  * NCR Microelectronics
  32  * 1635 Aeroplaza Drive
  33  * Colorado Springs, CO 80916
  34  * 1+ (719) 578-3400
  35  * 1+ (800) 334-5454
  36  */
  37 
  38 /*
  39  * Options : 
  40  * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
  41  *      for commands that return with a CHECK CONDITION status. 
  42  *
  43  * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
  44  * increase compared to polled I/O.
  45  *
  46  * PARITY - enable parity checking.  Not supported.
  47  * 
  48  * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
  49  *
  50  *
  51  * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
  52  *          only really want to use this if you're having a problem with
  53  *          dropped characters during high speed communications, and even
  54  *          then, you're going to be better off twiddling with transfersize.
  55  *
  56  * USLEEP - enable support for devices that don't disconnect.  Untested.
  57  *
  58  * The card is detected and initialized in one of several ways : 
  59  * 1.  Autoprobe (default) - There are many different models of
  60  *     the Pro Audio Spectrum/Studio 16, and I only have one of
  61  *     them, so this may require a little tweaking.  An interrupt
  62  *     is triggered to autoprobe for the interrupt line.  Note:
  63  *     with the newer model boards, the interrupt is set via
  64  *     software after reset using the default_irq for the
  65  *     current board number.
  66  *
  67  *
  68  * 2.  With command line overrides - pas16=port,irq may be 
  69  *     used on the LILO command line to override the defaults.
  70  *     NOTE:  untested.
  71  *
  72  * 3.  With the PAS16_OVERRIDE compile time define.  This is 
  73  *     specified as an array of address, irq tupples.  Ie, for
  74  *     one board at the default 0x388 address, IRQ10, I could say 
  75  *     -DPAS16_OVERRIDE={{0x388, 10}}
  76  *     NOTE:  Also untested.
  77  *      
  78  *     Note that if the override methods are used, place holders must
  79  *     be specified for other boards in the system.
  80  * 
  81  */
  82  
  83 #include <asm/system.h>
  84 #include <linux/signal.h>
  85 #include <linux/sched.h>
  86 #include <asm/io.h>
  87 #include "../block/blk.h"
  88 #include "scsi.h"
  89 #include "hosts.h"
  90 #include "pas16.h"
  91 #define AUTOPROBE_IRQ
  92 #include "NCR5380.h"
  93 #include "constants.h"
  94 
  95 
  96 
  97 int scsi_irq_translate[] =
  98         { 0,  0,  1,  2,  3,  4,  5,  6, 0,  0,  7,  8,  9,  0, 10, 11 };
  99 
 100 /* The default_irqs array contains values used to set the irq into the
 101  * board via software (as must be done on newer model boards without
 102  * irq jumpers on the board).  The first value in the array will be
 103  * assigned to logical board 0, the next to board 1, etc.
 104  */
 105 int default_irqs[] = {  PAS16_DEFAULT_BOARD_1_IRQ,
 106                         PAS16_DEFAULT_BOARD_2_IRQ,
 107                         PAS16_DEFAULT_BOARD_3_IRQ,
 108                         PAS16_DEFAULT_BOARD_4_IRQ
 109                      };
 110 
 111 static struct override {
 112     unsigned short io_port;
 113     int  irq;
 114 } overrides 
 115 #ifdef PAS16_OVERRIDE
 116     [] = PAS16_OVERRIDE;
 117 #else
 118     [4] = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
 119         {0,IRQ_AUTO}};
 120 #endif
 121 
 122 #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
 123 
 124 static struct base {
 125     unsigned short io_port;
 126     int noauto;
 127 } bases[] = { {PAS16_DEFAULT_BASE_1, 0},
 128               {PAS16_DEFAULT_BASE_2, 0},
 129               {PAS16_DEFAULT_BASE_3, 0},
 130               {PAS16_DEFAULT_BASE_4, 0}
 131             };
 132 
 133 #define NO_BASES (sizeof (bases) / sizeof (struct base))
 134 
 135 unsigned short  pas16_offset[ 8 ] =
 136     {
 137         0x1c00,    /* OUTPUT_DATA_REG */
 138         0x1c01,    /* INITIATOR_COMMAND_REG */
 139         0x1c02,    /* MODE_REG */
 140         0x1c03,    /* TARGET_COMMAND_REG */
 141         0x3c00,    /* STATUS_REG ro, SELECT_ENABLE_REG wo */
 142         0x3c01,    /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
 143         0x3c02,    /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
 144                     * START_DMA_TARGET_RECIEVE_REG wo
 145                     */
 146         0x3c03,    /* RESET_PARITY_INTERRUPT_REG ro,
 147                     * START_DMA_INITIATOR_RECIEVE_REG wo
 148                     */
 149     };
 150 
 151 
 152 
 153 /*
 154  * Function : enable_board( int  board_num, unsigned short port )
 155  *
 156  * Purpose :  set address in new model board
 157  *
 158  * Inputs : board_num - logical board number 0-3, port - base address
 159  *
 160  */
 161 
 162 void    enable_board( int  board_num,  unsigned short port )
     /* [previous][next][first][last][top][bottom][index][help] */
 163 {
 164     outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
 165     outb( port >> 2, MASTER_ADDRESS_PTR );
 166 }
 167 
 168 
 169 
 170 /*
 171  * Function : init_board( unsigned short port, int irq )
 172  *
 173  * Purpose :  Set the board up to handle the SCSI interface
 174  *
 175  * Inputs : port - base address of the board,
 176  *          irq - irq to assign to the SCSI port
 177  *
 178  */
 179 
 180 void    init_board( unsigned short io_port, int irq )
     /* [previous][next][first][last][top][bottom][index][help] */
 181 {
 182         unsigned int    tmp;
 183 
 184         /* Initialize the SCSI part of the board */
 185 
 186         outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG );  /* Timeout counter */
 187         outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET );   /* Reset TC */
 188         outb( 0x01, io_port + WAIT_STATE );   /* 1 Wait state */
 189 
 190         NCR5380_read( RESET_PARITY_INTERRUPT_REG );
 191 
 192         /* Set the SCSI interrupt pointer without mucking up the sound
 193          * interrupt pointer in the same byte.
 194          */
 195         tmp = inb( io_port + IO_CONFIG_3 );
 196         tmp = (  tmp & 0x0f ) | ( scsi_irq_translate[irq] << 4 );
 197         outb( tmp, io_port + IO_CONFIG_3 );
 198 
 199         /* Set up the drive parameters and enable 5380 interrupts */
 200         outb( 0x6d, io_port + SYS_CONFIG_4 );
 201 }
 202 
 203 
 204 /*
 205  * Function : pas16_hw_detect( unsigned short board_num )
 206  *
 207  * Purpose : determine if a pas16 board is present
 208  * 
 209  * Inputs : board_num - logical board number ( 0 - 3 )
 210  *
 211  * Returns : 0 if board not found, 1 if found.
 212  */
 213 
 214 int     pas16_hw_detect( unsigned short  board_num )
     /* [previous][next][first][last][top][bottom][index][help] */
 215 {
 216     unsigned char       board_rev, tmp;
 217     unsigned short      port = bases[ board_num ].io_port;
 218 
 219     /* See if we can find a PAS16 board at the address associated
 220      * with this logical board number.
 221      */
 222 
 223     /* First, attempt to take a newer model board out of reset and
 224      * give it a base address.  This shouldn't affect older boards.
 225      */
 226     enable_board( board_num, port );
 227 
 228     /* Now see if it looks like a PAS16 board */
 229     board_rev = inb( port + PCB_CONFIG );
 230 
 231     if( board_rev == 0xff )
 232         return 0;
 233 
 234     tmp = board_rev ^ 0xe0;
 235 
 236     outb( tmp, port + PCB_CONFIG );
 237     tmp = inb( port + PCB_CONFIG );
 238     outb( board_rev, port + PCB_CONFIG );
 239 
 240     if( board_rev != tmp )      /* Not a PAS-16 */
 241         return 0;
 242 
 243     if( ( inb( port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 ) 
 244         return 0;       /* return if no SCSI interface found */
 245 
 246     return 1;
 247 }
 248 
 249 
 250 /*
 251  * Function : pas16_setup(char *str, int *ints)
 252  *
 253  * Purpose : LILO command line initialization of the overrides array,
 254  * 
 255  * Inputs : str - unused, ints - array of integer paramters with ints[0]
 256  *      equal to the number of ints.
 257  *
 258  */
 259 
 260 void pas16_setup(char *str, int *ints) {
     /* [previous][next][first][last][top][bottom][index][help] */
 261     static int commandline_current = 0;
 262     int i;
 263     if (ints[0] != 2) 
 264         printk("pas16_setup : usage pas16=io_port,irq\n");
 265     else 
 266         if (commandline_current < NO_OVERRIDES) {
 267             overrides[commandline_current].io_port = (unsigned short) ints[1];
 268             overrides[commandline_current].irq = ints[2];
 269             for (i = 0; i < NO_BASES; ++i)
 270                 if (bases[i].io_port == (unsigned short) ints[1]) {
 271                     bases[i].noauto = 1;
 272                     break;
 273                 }
 274             ++commandline_current;
 275         }
 276 }
 277 
 278 static struct sigaction pas16_sigaction =  { pas16_intr, 0, SA_INTERRUPT , NULL };
 279 
 280 /* 
 281  * Function : int pas16_detect(int hostno)
 282  *
 283  * Purpose : detects and initializes PAS16 controllers
 284  *      that were autoprobed, overriden on the LILO command line, 
 285  *      or specified at compile time.
 286  *
 287  * Inputs : hostno - id of this SCSI adapter.
 288  * 
 289  * Returns : 1 if a host adapter was found, 0 if not.
 290  *
 291  */
 292 
 293 int pas16_detect(int hostno) {
     /* [previous][next][first][last][top][bottom][index][help] */
 294     static int current_override = 0;
 295     static unsigned short current_base = 0;
 296     struct Scsi_Host *instance;
 297     unsigned short io_port;
 298     int  count;
 299 
 300     for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
 301         io_port = 0;
 302 
 303         if (overrides[current_override].io_port)
 304         {
 305             io_port = overrides[current_override].io_port;
 306             enable_board( current_override, io_port );
 307             init_board( io_port, overrides[current_override].irq );
 308         }
 309         else
 310             for (; !io_port && (current_base < NO_BASES); ++current_base) {
 311 #if (PDEBUG & PDEBUG_INIT)
 312     printk("scsi%d : probing io_port %04x\n", hostno, (unsigned int) bases[current_base].io_port);
 313 #endif
 314                 if ( !bases[current_base].noauto &&
 315                      pas16_hw_detect( current_base ) ){
 316                         io_port = bases[current_base].io_port;
 317                         init_board( io_port, default_irqs[ current_base ] ); 
 318 #if (PDEBUG & PDEBUG_INIT)
 319                         printk("scsi%d : detected board.\n", hostno);
 320 #endif
 321                 }
 322     }
 323 
 324 
 325 #if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
 326         printk("scsi%d : io_port = %04x\n", hostno, (unsigned int) io_port);
 327 #endif
 328 
 329         if (!io_port)
 330             break;
 331 
 332         instance = scsi_register (hostno, sizeof(struct NCR5380_hostdata));
 333         instance->io_port = io_port;
 334 
 335         NCR5380_init(instance);
 336 
 337         if (overrides[current_override].irq != IRQ_AUTO)
 338             instance->irq = overrides[current_override].irq;
 339         else 
 340             instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
 341 
 342         if (instance->irq != IRQ_NONE) 
 343             if (irqaction (instance->irq, &pas16_sigaction)) {
 344                 printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
 345                     hostno, instance->irq);
 346                 instance->irq = IRQ_NONE;
 347             } 
 348 
 349         if (instance->irq == IRQ_NONE) {
 350             printk("scsi%d : interrupts not enabled. for better interactive performance,\n", hostno);
 351             printk("scsi%d : please jumper the board for a free IRQ.\n", hostno);
 352         }
 353 
 354 #if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
 355         printk("scsi%d : irq = %d\n", hostno, instance->irq);
 356 #endif
 357 
 358         printk("scsi%d : at 0x%04x", instance->host_no, (int) 
 359             instance->io_port);
 360         if (instance->irq == IRQ_NONE)
 361             printk (" interrupts disabled");
 362         else 
 363             printk (" irq %d", instance->irq);
 364         printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
 365             CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE);
 366         NCR5380_print_options(instance);
 367         printk("\n");
 368 
 369         ++current_override;
 370         ++count;
 371         ++hostno;
 372     }
 373     return count;
 374 }
 375 
 376 /*
 377  * Function : int pas16_biosparam(int size, int dev, int *ip)
 378  *
 379  * Purpose : Generates a BIOS / DOS compatable H-C-S mapping for 
 380  *      the specified device / size.
 381  * 
 382  * Inputs : size = size of device in sectors (512 bytes), dev = block device
 383  *      major / minor, ip[] = {heads, sectors, cylinders}  
 384  *
 385  * Returns : allways 0 (success), initializes ip
 386  *      
 387  */
 388 
 389 /* 
 390  * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
 391  * using hard disks on a trantor should verify that this mapping corresponds
 392  * to that used by the BIOS / ASPI driver by running the linux fdisk program
 393  * and matching the H_C_S coordinates to what DOS uses.
 394  */
 395 
 396 int pas16_biosparam(int size, int dev, int * ip)
     /* [previous][next][first][last][top][bottom][index][help] */
 397 {
 398   ip[0] = 64;
 399   ip[1] = 32;
 400   ip[2] = size >> 11;
 401   return 0;
 402 }
 403 
 404 /*
 405  * Function : int NCR5380_pread (struct Scsi_Host *instance, 
 406  *      unsigned char *dst, int len)
 407  *
 408  * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to 
 409  *      dst
 410  * 
 411  * Inputs : dst = destination, len = length in bytes
 412  *
 413  * Returns : 0 on success, non zero on a failure such as a watchdog 
 414  *      timeout.
 415  */
 416 
 417 static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
     /* [previous][next][first][last][top][bottom][index][help] */
 418     int len) {
 419     register unsigned char  *d = dst;
 420     register unsigned short reg = (unsigned short) (instance->io_port + 
 421         P_DATA_REG_OFFSET);
 422     register i = len;
 423 
 424     while ( inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY );
 425 
 426     for (; i; --i) 
 427         *d++ = (unsigned char) inb(reg);
 428 
 429     if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
 430         outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
 431         printk("scsi%d : watchdog timer fired in NCR5480_pread()\n",
 432             instance->host_no);
 433         return -1;
 434     } else
 435         return 0;
 436 }
 437 
 438 /*
 439  * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
 440  *      unsigned char *src, int len)
 441  *
 442  * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
 443  *      src
 444  * 
 445  * Inputs : src = source, len = length in bytes
 446  *
 447  * Returns : 0 on success, non zero on a failure such as a watchdog 
 448  *      timeout.
 449  */
 450 
 451 static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
     /* [previous][next][first][last][top][bottom][index][help] */
 452     int len) {
 453     register unsigned char *s = src;
 454     register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
 455     register i = len;
 456 
 457     while ( ( inb( instance->io_port + P_STATUS_REG_OFFSET ) ) & P_ST_RDY );
 458     for (; i; --i)
 459         outb( *s++, reg );
 460 
 461     if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
 462         outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
 463         printk("scsi%d : watchdog timer fired in NCR5480_pwrite()\n",
 464             instance->host_no);
 465         return -1;
 466     } else 
 467         return 0;
 468 }
 469 
 470 /*
 471  * Function : const char *pas16_info(void)
 472  *
 473  * Purpose : provide furthur information about this driver.
 474  *
 475  * Returns : an empty string.
 476  */
 477 
 478 const char *pas16_info (void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 479     static const char string[]="";
 480     return string;
 481 }
 482 
 483 #include "NCR5380.c"

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