OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [scsi/] [pas16.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
#define AUTOSENSE
2
#define PSEUDO_DMA
3
#define FOO
4
#define UNSAFE  /* Not unsafe for PAS16 -- use it */
5
 
6
/*
7
 * This driver adapted from Drew Eckhardt's Trantor T128 driver
8
 *
9
 * Copyright 1993, Drew Eckhardt
10
 *      Visionary Computing
11
 *      (Unix and Linux consulting and custom programming)
12
 *      drew@colorado.edu
13
 *      +1 (303) 666-5836
14
 *
15
 *  ( Based on T128 - DISTRIBUTION RELEASE 3. )
16
 *
17
 * Modified to work with the Pro Audio Spectrum/Studio 16
18
 * by John Weidman.
19
 *
20
 *
21
 * For more information, please consult
22
 *
23
 * Media Vision
24
 * (510) 770-8600
25
 * (800) 348-7116
26
 *
27
 * and
28
 *
29
 * NCR 5380 Family
30
 * SCSI Protocol Controller
31
 * Databook
32
 *
33
 * NCR Microelectronics
34
 * 1635 Aeroplaza Drive
35
 * Colorado Springs, CO 80916
36
 * 1+ (719) 578-3400
37
 * 1+ (800) 334-5454
38
 */
39
 
40
/*
41
 * Options :
42
 * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
43
 *      for commands that return with a CHECK CONDITION status.
44
 *
45
 * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
46
 *      bytes at a time.  Since interrupts are disabled by default during
47
 *      these transfers, we might need this to give reasonable interrupt
48
 *      service time if the transfer size gets too large.
49
 *
50
 * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
51
 * increase compared to polled I/O.
52
 *
53
 * PARITY - enable parity checking.  Not supported.
54
 *
55
 * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
56
 *
57
 * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  This
58
 *          parameter comes from the NCR5380 code.  It is NOT unsafe with
59
 *          the PAS16 and you should use it.  If you don't you will have
60
 *          a problem with dropped characters during high speed
61
 *          communications during SCSI transfers.  If you really don't
62
 *          want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or
63
 *          twiddle with the transfer size in the high level code.
64
 *
65
 * USLEEP - enable support for devices that don't disconnect.  Untested.
66
 *
67
 * The card is detected and initialized in one of several ways :
68
 * 1.  Autoprobe (default) - There are many different models of
69
 *     the Pro Audio Spectrum/Studio 16, and I only have one of
70
 *     them, so this may require a little tweaking.  An interrupt
71
 *     is triggered to autoprobe for the interrupt line.  Note:
72
 *     with the newer model boards, the interrupt is set via
73
 *     software after reset using the default_irq for the
74
 *     current board number.
75
 *
76
 *
77
 * 2.  With command line overrides - pas16=port,irq may be
78
 *     used on the LILO command line to override the defaults.
79
 *
80
 * 3.  With the PAS16_OVERRIDE compile time define.  This is
81
 *     specified as an array of address, irq tuples.  Ie, for
82
 *     one board at the default 0x388 address, IRQ10, I could say
83
 *     -DPAS16_OVERRIDE={{0x388, 10}}
84
 *     NOTE:  Untested.
85
 *
86
 *     Note that if the override methods are used, place holders must
87
 *     be specified for other boards in the system.
88
 *
89
 *
90
 * Configuration notes :
91
 *   The current driver does not support interrupt sharing with the
92
 *   sound portion of the card.  If you use the same irq for the
93
 *   scsi port and sound you will have problems.  Either use
94
 *   a different irq for the scsi port or don't use interrupts
95
 *   for the scsi port.
96
 *
97
 *   If you have problems with your card not being recognized, use
98
 *   the LILO command line override.  Try to get it recognized without
99
 *   interrupts.  Ie, for a board at the default 0x388 base port,
100
 *   boot: linux pas16=0x388,255
101
 *
102
 *     (255 is the IRQ_NONE constant in NCR5380.h)
103
 */
104
 
105
#ifdef MODULE
106
#include <linux/module.h>
107
#endif
108
 
109
#include <asm/system.h>
110
#include <linux/signal.h>
111
#include <linux/proc_fs.h>
112
#include <linux/sched.h>
113
#include <asm/io.h>
114
#include <linux/blk.h>
115
#include "scsi.h"
116
#include "hosts.h"
117
#include "pas16.h"
118
#define AUTOPROBE_IRQ
119
#include "NCR5380.h"
120
#include "constants.h"
121
#include "sd.h"
122
 
123
#include<linux/stat.h>
124
 
125
struct proc_dir_entry proc_scsi_pas16 = {
126
    PROC_SCSI_PAS16, 5, "pas16",
127
    S_IFDIR | S_IRUGO | S_IXUGO, 2
128
};
129
static int pas_maxi = 0;
130
static int pas_wmaxi = 0;
131
 
132
 
133
int scsi_irq_translate[] =
134
        { 0,  0,  1,  2,  3,  4,  5,  6, 0,  0,  7,  8,  9,  0, 10, 11 };
135
 
136
/* The default_irqs array contains values used to set the irq into the
137
 * board via software (as must be done on newer model boards without
138
 * irq jumpers on the board).  The first value in the array will be
139
 * assigned to logical board 0, the next to board 1, etc.
140
 */
141
int default_irqs[] = {  PAS16_DEFAULT_BOARD_1_IRQ,
142
                        PAS16_DEFAULT_BOARD_2_IRQ,
143
                        PAS16_DEFAULT_BOARD_3_IRQ,
144
                        PAS16_DEFAULT_BOARD_4_IRQ
145
                     };
146
 
147
static struct override {
148
    unsigned short io_port;
149
    int  irq;
150
} overrides
151
#ifdef PAS16_OVERRIDE
152
    [] = PAS16_OVERRIDE;
153
#else
154
    [4] = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
155
        {0,IRQ_AUTO}};
156
#endif
157
 
158
#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
159
 
160
static struct base {
161
    unsigned short io_port;
162
    int noauto;
163
} bases[] = { {PAS16_DEFAULT_BASE_1, 0},
164
              {PAS16_DEFAULT_BASE_2, 0},
165
              {PAS16_DEFAULT_BASE_3, 0},
166
              {PAS16_DEFAULT_BASE_4, 0}
167
            };
168
 
169
#define NO_BASES (sizeof (bases) / sizeof (struct base))
170
 
171
unsigned short  pas16_offset[ 8 ] =
172
    {
173
        0x1c00,    /* OUTPUT_DATA_REG */
174
        0x1c01,    /* INITIATOR_COMMAND_REG */
175
        0x1c02,    /* MODE_REG */
176
        0x1c03,    /* TARGET_COMMAND_REG */
177
        0x3c00,    /* STATUS_REG ro, SELECT_ENABLE_REG wo */
178
        0x3c01,    /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
179
        0x3c02,    /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
180
                    * START_DMA_TARGET_RECEIVE_REG wo
181
                    */
182
        0x3c03,    /* RESET_PARITY_INTERRUPT_REG ro,
183
                    * START_DMA_INITIATOR_RECEIVE_REG wo
184
                    */
185
    };
186
/*----------------------------------------------------------------*/
187
/* the following will set the monitor border color (useful to find
188
 where something crashed or gets stuck at */
189
/* 1 = blue
190
 2 = green
191
 3 = cyan
192
 4 = red
193
 5 = magenta
194
 6 = yellow
195
 7 = white
196
*/
197
#if 1
198
#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
199
#else
200
#define rtrc(i) {}
201
#endif
202
 
203
 
204
/*
205
 * Function : enable_board( int  board_num, unsigned short port )
206
 *
207
 * Purpose :  set address in new model board
208
 *
209
 * Inputs : board_num - logical board number 0-3, port - base address
210
 *
211
 */
212
 
213
void    enable_board( int  board_num,  unsigned short port )
214
{
215
    outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
216
    outb( port >> 2, MASTER_ADDRESS_PTR );
217
}
218
 
219
 
220
 
221
/*
222
 * Function : init_board( unsigned short port, int irq )
223
 *
224
 * Purpose :  Set the board up to handle the SCSI interface
225
 *
226
 * Inputs : port - base address of the board,
227
 *          irq - irq to assign to the SCSI port
228
 *          force_irq - set it even if it conflicts with sound driver
229
 *
230
 */
231
 
232
void    init_board( unsigned short io_port, int irq, int force_irq )
233
{
234
        unsigned int    tmp;
235
        unsigned int    pas_irq_code;
236
 
237
        /* Initialize the SCSI part of the board */
238
 
239
        outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG );  /* Timeout counter */
240
        outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET );   /* Reset TC */
241
        outb( 0x01, io_port + WAIT_STATE );   /* 1 Wait state */
242
 
243
        NCR5380_read( RESET_PARITY_INTERRUPT_REG );
244
 
245
        /* Set the SCSI interrupt pointer without mucking up the sound
246
         * interrupt pointer in the same byte.
247
         */
248
        pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0;
249
        tmp = inb( io_port + IO_CONFIG_3 );
250
 
251
        if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0
252
            && !force_irq )
253
        {
254
            printk( "pas16: WARNING: Can't use same irq as sound "
255
                    "driver -- interrupts disabled\n" );
256
            /* Set up the drive parameters, disable 5380 interrupts */
257
            outb( 0x4d, io_port + SYS_CONFIG_4 );
258
        }
259
        else
260
        {
261
            tmp = (  tmp & 0x0f ) | ( pas_irq_code << 4 );
262
            outb( tmp, io_port + IO_CONFIG_3 );
263
 
264
            /* Set up the drive parameters and enable 5380 interrupts */
265
            outb( 0x6d, io_port + SYS_CONFIG_4 );
266
        }
267
}
268
 
269
 
270
/*
271
 * Function : pas16_hw_detect( unsigned short board_num )
272
 *
273
 * Purpose : determine if a pas16 board is present
274
 *
275
 * Inputs : board_num - logical board number ( 0 - 3 )
276
 *
277
 * Returns : 0 if board not found, 1 if found.
278
 */
279
 
280
int     pas16_hw_detect( unsigned short  board_num )
281
{
282
    unsigned char       board_rev, tmp;
283
    unsigned short      io_port = bases[ board_num ].io_port;
284
 
285
    /* See if we can find a PAS16 board at the address associated
286
     * with this logical board number.
287
     */
288
 
289
    /* First, attempt to take a newer model board out of reset and
290
     * give it a base address.  This shouldn't affect older boards.
291
     */
292
    enable_board( board_num, io_port );
293
 
294
    /* Now see if it looks like a PAS16 board */
295
    board_rev = inb( io_port + PCB_CONFIG );
296
 
297
    if( board_rev == 0xff )
298
        return 0;
299
 
300
    tmp = board_rev ^ 0xe0;
301
 
302
    outb( tmp, io_port + PCB_CONFIG );
303
    tmp = inb( io_port + PCB_CONFIG );
304
    outb( board_rev, io_port + PCB_CONFIG );
305
 
306
    if( board_rev != tmp )      /* Not a PAS-16 */
307
        return 0;
308
 
309
    if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 )
310
        return 0;        /* return if no SCSI interface found */
311
 
312
    /* Mediavision has some new model boards that return ID bits
313
     * that indicate a SCSI interface, but they're not (LMS).  We'll
314
     * put in an additional test to try to weed them out.
315
     */
316
 
317
    outb( 0x01, io_port + WAIT_STATE );         /* 1 Wait state */
318
    NCR5380_write( MODE_REG, 0x20 );            /* Is it really SCSI? */
319
    if( NCR5380_read( MODE_REG ) != 0x20 )      /* Write to a reg.    */
320
        return 0;                                /* and try to read    */
321
    NCR5380_write( MODE_REG, 0x00 );            /* it back.           */
322
    if( NCR5380_read( MODE_REG ) != 0x00 )
323
        return 0;
324
 
325
    return 1;
326
}
327
 
328
 
329
/*
330
 * Function : pas16_setup(char *str, int *ints)
331
 *
332
 * Purpose : LILO command line initialization of the overrides array,
333
 *
334
 * Inputs : str - unused, ints - array of integer parameters with ints[0]
335
 *      equal to the number of ints.
336
 *
337
 */
338
 
339
void pas16_setup(char *str, int *ints) {
340
    static int commandline_current = 0;
341
    int i;
342
    if (ints[0] != 2)
343
        printk("pas16_setup : usage pas16=io_port,irq\n");
344
    else
345
        if (commandline_current < NO_OVERRIDES) {
346
            overrides[commandline_current].io_port = (unsigned short) ints[1];
347
            overrides[commandline_current].irq = ints[2];
348
            for (i = 0; i < NO_BASES; ++i)
349
                if (bases[i].io_port == (unsigned short) ints[1]) {
350
                    bases[i].noauto = 1;
351
                    break;
352
                }
353
            ++commandline_current;
354
        }
355
}
356
 
357
/*
358
 * Function : int pas16_detect(Scsi_Host_Template * tpnt)
359
 *
360
 * Purpose : detects and initializes PAS16 controllers
361
 *      that were autoprobed, overridden on the LILO command line,
362
 *      or specified at compile time.
363
 *
364
 * Inputs : tpnt - template for this SCSI adapter.
365
 *
366
 * Returns : 1 if a host adapter was found, 0 if not.
367
 *
368
 */
369
 
370
int pas16_detect(Scsi_Host_Template * tpnt) {
371
    static int current_override = 0;
372
    static unsigned short current_base = 0;
373
    struct Scsi_Host *instance;
374
    unsigned short io_port;
375
    int  count;
376
 
377
    tpnt->proc_dir = &proc_scsi_pas16;
378
    tpnt->proc_info = &pas16_proc_info;
379
 
380
    for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
381
        io_port = 0;
382
 
383
        if (overrides[current_override].io_port)
384
        {
385
            io_port = overrides[current_override].io_port;
386
            enable_board( current_override, io_port );
387
            init_board( io_port, overrides[current_override].irq, 1 );
388
        }
389
        else
390
            for (; !io_port && (current_base < NO_BASES); ++current_base) {
391
#if (PDEBUG & PDEBUG_INIT)
392
    printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port);
393
#endif
394
                if ( !bases[current_base].noauto &&
395
                     pas16_hw_detect( current_base ) ){
396
                        io_port = bases[current_base].io_port;
397
                        init_board( io_port, default_irqs[ current_base ], 0 );
398
#if (PDEBUG & PDEBUG_INIT)
399
                        printk("scsi-pas16 : detected board.\n");
400
#endif
401
                }
402
    }
403
 
404
 
405
#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
406
        printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port);
407
#endif
408
 
409
        if (!io_port)
410
            break;
411
 
412
        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
413
        instance->io_port = io_port;
414
 
415
        NCR5380_init(instance, 0);
416
 
417
        if (overrides[current_override].irq != IRQ_AUTO)
418
            instance->irq = overrides[current_override].irq;
419
        else
420
            instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
421
 
422
        if (instance->irq != IRQ_NONE)
423
            if (request_irq(instance->irq, pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
424
                printk("scsi%d : IRQ%d not free, interrupts disabled\n",
425
                    instance->host_no, instance->irq);
426
                instance->irq = IRQ_NONE;
427
            }
428
 
429
        if (instance->irq == IRQ_NONE) {
430
            printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
431
            printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
432
            /* Disable 5380 interrupts, leave drive params the same */
433
            outb( 0x4d, io_port + SYS_CONFIG_4 );
434
            outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
435
        }
436
 
437
#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
438
        printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
439
#endif
440
 
441
        printk("scsi%d : at 0x%04x", instance->host_no, (int)
442
            instance->io_port);
443
        if (instance->irq == IRQ_NONE)
444
            printk (" interrupts disabled");
445
        else
446
            printk (" irq %d", instance->irq);
447
        printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
448
            CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE);
449
        NCR5380_print_options(instance);
450
        printk("\n");
451
 
452
        ++current_override;
453
        ++count;
454
    }
455
    return count;
456
}
457
 
458
/*
459
 * Function : int pas16_biosparam(Disk *disk, kdev_t dev, int *ip)
460
 *
461
 * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for
462
 *      the specified device / size.
463
 *
464
 * Inputs : size = size of device in sectors (512 bytes), dev = block device
465
 *      major / minor, ip[] = {heads, sectors, cylinders}
466
 *
467
 * Returns : always 0 (success), initializes ip
468
 *
469
 */
470
 
471
/*
472
 * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
473
 * using hard disks on a trantor should verify that this mapping corresponds
474
 * to that used by the BIOS / ASPI driver by running the linux fdisk program
475
 * and matching the H_C_S coordinates to what DOS uses.
476
 */
477
 
478
int pas16_biosparam(Disk * disk, kdev_t dev, int * ip)
479
{
480
  int size = disk->capacity;
481
  ip[0] = 64;
482
  ip[1] = 32;
483
  ip[2] = size >> 11;           /* I think I have it as /(32*64) */
484
  if( ip[2] > 1024 ) {          /* yes, >, not >= */
485
        ip[0]=255;
486
        ip[1]=63;
487
        ip[2]=size/(63*255);
488
        if( ip[2] > 1023 )      /* yes >1023... */
489
                ip[2] = 1023;
490
  }
491
 
492
  return 0;
493
}
494
 
495
/*
496
 * Function : int NCR5380_pread (struct Scsi_Host *instance,
497
 *      unsigned char *dst, int len)
498
 *
499
 * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to
500
 *      dst
501
 *
502
 * Inputs : dst = destination, len = length in bytes
503
 *
504
 * Returns : 0 on success, non zero on a failure such as a watchdog
505
 *      timeout.
506
 */
507
 
508
static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
509
    int len) {
510
    register unsigned char  *d = dst;
511
    register unsigned short reg = (unsigned short) (instance->io_port +
512
        P_DATA_REG_OFFSET);
513
    register int i = len;
514
    int ii = 0;
515
 
516
    while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) )
517
         ++ii;
518
 
519
    insb( reg, d, i );
520
 
521
    if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
522
        outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
523
        printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
524
            instance->host_no);
525
        return -1;
526
    }
527
   if (ii > pas_maxi)
528
      pas_maxi = ii;
529
    return 0;
530
}
531
 
532
/*
533
 * Function : int NCR5380_pwrite (struct Scsi_Host *instance,
534
 *      unsigned char *src, int len)
535
 *
536
 * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
537
 *      src
538
 *
539
 * Inputs : src = source, len = length in bytes
540
 *
541
 * Returns : 0 on success, non zero on a failure such as a watchdog
542
 *      timeout.
543
 */
544
 
545
static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
546
    int len) {
547
    register unsigned char *s = src;
548
    register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
549
    register int i = len;
550
    int ii = 0;
551
 
552
    while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) )
553
         ++ii;
554
 
555
    outsb( reg, s, i );
556
 
557
    if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
558
        outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
559
        printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
560
            instance->host_no);
561
        return -1;
562
    }
563
    if (ii > pas_maxi)
564
         pas_wmaxi = ii;
565
    return 0;
566
}
567
 
568
#include "NCR5380.c"
569
 
570
#ifdef MODULE
571
/* Eventually this will go into an include file, but this will be later */
572
Scsi_Host_Template driver_template = MV_PAS16;
573
 
574
#include <linux/module.h>
575
#include "scsi_module.c"
576
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.