4
#define UNSAFE /* Not unsafe for PAS16 -- use it */
8
* This driver adapted from Drew Eckhardt's Trantor T128 driver
10
* Copyright 1993, Drew Eckhardt
12
* (Unix and Linux consulting and custom programming)
16
* ( Based on T128 - DISTRIBUTION RELEASE 3. )
18
* Modified to work with the Pro Audio Spectrum/Studio 16
22
* For more information, please consult
31
* SCSI Protocol Controller
34
* NCR Microelectronics
35
* 1635 Aeroplaza Drive
36
* Colorado Springs, CO 80916
43
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
44
* for commands that return with a CHECK CONDITION status.
46
* LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
47
* bytes at a time. Since interrupts are disabled by default during
48
* these transfers, we might need this to give reasonable interrupt
49
* service time if the transfer size gets too large.
51
* PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
52
* increase compared to polled I/O.
54
* PARITY - enable parity checking. Not supported.
56
* SCSI2 - enable support for SCSI-II tagged queueing. Untested.
58
* UNSAFE - leave interrupts enabled during pseudo-DMA transfers. This
59
* parameter comes from the NCR5380 code. It is NOT unsafe with
60
* the PAS16 and you should use it. If you don't you will have
61
* a problem with dropped characters during high speed
62
* communications during SCSI transfers. If you really don't
63
* want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or
64
* twiddle with the transfer size in the high level code.
66
* USLEEP - enable support for devices that don't disconnect. Untested.
68
* The card is detected and initialized in one of several ways :
69
* 1. Autoprobe (default) - There are many different models of
70
* the Pro Audio Spectrum/Studio 16, and I only have one of
71
* them, so this may require a little tweaking. An interrupt
72
* is triggered to autoprobe for the interrupt line. Note:
73
* with the newer model boards, the interrupt is set via
74
* software after reset using the default_irq for the
75
* current board number.
77
* 2. With command line overrides - pas16=port,irq may be
78
* used on the LILO command line to override the defaults.
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}}
86
* 4. When included as a module, with arguments passed on the command line:
87
* pas16_irq=xx the interrupt
88
* pas16_addr=xx the port
89
* e.g. "modprobe pas16 pas16_addr=0x388 pas16_irq=5"
91
* Note that if the override methods are used, place holders must
92
* be specified for other boards in the system.
95
* Configuration notes :
96
* The current driver does not support interrupt sharing with the
97
* sound portion of the card. If you use the same irq for the
98
* scsi port and sound you will have problems. Either use
99
* a different irq for the scsi port or don't use interrupts
102
* If you have problems with your card not being recognized, use
103
* the LILO command line override. Try to get it recognized without
104
* interrupts. Ie, for a board at the default 0x388 base port,
105
* boot: linux pas16=0x388,255
107
* SCSI_IRQ_NONE (255) should be specified for no interrupt,
108
* IRQ_AUTO (254) to autoprobe for an IRQ line if overridden
109
* on the command line.
111
* (IRQ_AUTO == 254, SCSI_IRQ_NONE == 255 in NCR5380.h)
114
#include <linux/module.h>
116
#include <asm/system.h>
117
#include <linux/signal.h>
118
#include <linux/proc_fs.h>
121
#include <linux/blkdev.h>
122
#include <linux/delay.h>
123
#include <linux/interrupt.h>
124
#include <linux/stat.h>
125
#include <linux/init.h>
128
#include <scsi/scsi_host.h>
130
#define AUTOPROBE_IRQ
134
static int pas_maxi = 0;
135
static int pas_wmaxi = 0;
136
static unsigned short pas16_addr = 0;
137
static int pas16_irq = 0;
140
static const int scsi_irq_translate[] =
141
{ 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 };
143
/* The default_irqs array contains values used to set the irq into the
144
* board via software (as must be done on newer model boards without
145
* irq jumpers on the board). The first value in the array will be
146
* assigned to logical board 0, the next to board 1, etc.
148
static int default_irqs[] __initdata =
149
{ PAS16_DEFAULT_BOARD_1_IRQ,
150
PAS16_DEFAULT_BOARD_2_IRQ,
151
PAS16_DEFAULT_BOARD_3_IRQ,
152
PAS16_DEFAULT_BOARD_4_IRQ
155
static struct override {
156
unsigned short io_port;
159
#ifdef PAS16_OVERRIDE
160
[] __initdata = PAS16_OVERRIDE;
162
[4] __initdata = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
166
#define NO_OVERRIDES ARRAY_SIZE(overrides)
169
unsigned short io_port;
171
} bases[] __initdata =
172
{ {PAS16_DEFAULT_BASE_1, 0},
173
{PAS16_DEFAULT_BASE_2, 0},
174
{PAS16_DEFAULT_BASE_3, 0},
175
{PAS16_DEFAULT_BASE_4, 0}
178
#define NO_BASES ARRAY_SIZE(bases)
180
static const unsigned short pas16_offset[ 8 ] =
182
0x1c00, /* OUTPUT_DATA_REG */
183
0x1c01, /* INITIATOR_COMMAND_REG */
184
0x1c02, /* MODE_REG */
185
0x1c03, /* TARGET_COMMAND_REG */
186
0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */
187
0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
188
0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
189
* START_DMA_TARGET_RECEIVE_REG wo
191
0x3c03, /* RESET_PARITY_INTERRUPT_REG ro,
192
* START_DMA_INITIATOR_RECEIVE_REG wo
195
/*----------------------------------------------------------------*/
196
/* the following will set the monitor border color (useful to find
197
where something crashed or gets stuck at */
207
#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
214
* Function : enable_board( int board_num, unsigned short port )
216
* Purpose : set address in new model board
218
* Inputs : board_num - logical board number 0-3, port - base address
223
enable_board( int board_num, unsigned short port )
225
outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
226
outb( port >> 2, MASTER_ADDRESS_PTR );
232
* Function : init_board( unsigned short port, int irq )
234
* Purpose : Set the board up to handle the SCSI interface
236
* Inputs : port - base address of the board,
237
* irq - irq to assign to the SCSI port
238
* force_irq - set it even if it conflicts with sound driver
243
init_board( unsigned short io_port, int irq, int force_irq )
246
unsigned int pas_irq_code;
248
/* Initialize the SCSI part of the board */
250
outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG ); /* Timeout counter */
251
outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */
252
outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
254
NCR5380_read( RESET_PARITY_INTERRUPT_REG );
256
/* Set the SCSI interrupt pointer without mucking up the sound
257
* interrupt pointer in the same byte.
259
pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0;
260
tmp = inb( io_port + IO_CONFIG_3 );
262
if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0
265
printk( "pas16: WARNING: Can't use same irq as sound "
266
"driver -- interrupts disabled\n" );
267
/* Set up the drive parameters, disable 5380 interrupts */
268
outb( 0x4d, io_port + SYS_CONFIG_4 );
272
tmp = ( tmp & 0x0f ) | ( pas_irq_code << 4 );
273
outb( tmp, io_port + IO_CONFIG_3 );
275
/* Set up the drive parameters and enable 5380 interrupts */
276
outb( 0x6d, io_port + SYS_CONFIG_4 );
282
* Function : pas16_hw_detect( unsigned short board_num )
284
* Purpose : determine if a pas16 board is present
286
* Inputs : board_num - logical board number ( 0 - 3 )
288
* Returns : 0 if board not found, 1 if found.
292
pas16_hw_detect( unsigned short board_num )
294
unsigned char board_rev, tmp;
295
unsigned short io_port = bases[ board_num ].io_port;
297
/* See if we can find a PAS16 board at the address associated
298
* with this logical board number.
301
/* First, attempt to take a newer model board out of reset and
302
* give it a base address. This shouldn't affect older boards.
304
enable_board( board_num, io_port );
306
/* Now see if it looks like a PAS16 board */
307
board_rev = inb( io_port + PCB_CONFIG );
309
if( board_rev == 0xff )
312
tmp = board_rev ^ 0xe0;
314
outb( tmp, io_port + PCB_CONFIG );
315
tmp = inb( io_port + PCB_CONFIG );
316
outb( board_rev, io_port + PCB_CONFIG );
318
if( board_rev != tmp ) /* Not a PAS-16 */
321
if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 )
322
return 0; /* return if no SCSI interface found */
324
/* Mediavision has some new model boards that return ID bits
325
* that indicate a SCSI interface, but they're not (LMS). We'll
326
* put in an additional test to try to weed them out.
329
outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
330
NCR5380_write( MODE_REG, 0x20 ); /* Is it really SCSI? */
331
if( NCR5380_read( MODE_REG ) != 0x20 ) /* Write to a reg. */
332
return 0; /* and try to read */
333
NCR5380_write( MODE_REG, 0x00 ); /* it back. */
334
if( NCR5380_read( MODE_REG ) != 0x00 )
342
* Function : pas16_setup(char *str, int *ints)
344
* Purpose : LILO command line initialization of the overrides array,
346
* Inputs : str - unused, ints - array of integer parameters with ints[0]
347
* equal to the number of ints.
351
void __init pas16_setup(char *str, int *ints)
353
static int commandline_current = 0;
356
printk("pas16_setup : usage pas16=io_port,irq\n");
358
if (commandline_current < NO_OVERRIDES) {
359
overrides[commandline_current].io_port = (unsigned short) ints[1];
360
overrides[commandline_current].irq = ints[2];
361
for (i = 0; i < NO_BASES; ++i)
362
if (bases[i].io_port == (unsigned short) ints[1]) {
366
++commandline_current;
371
* Function : int pas16_detect(struct scsi_host_template * tpnt)
373
* Purpose : detects and initializes PAS16 controllers
374
* that were autoprobed, overridden on the LILO command line,
375
* or specified at compile time.
377
* Inputs : tpnt - template for this SCSI adapter.
379
* Returns : 1 if a host adapter was found, 0 if not.
383
int __init pas16_detect(struct scsi_host_template * tpnt)
385
static int current_override = 0;
386
static unsigned short current_base = 0;
387
struct Scsi_Host *instance;
388
unsigned short io_port;
391
tpnt->proc_name = "pas16";
392
tpnt->proc_info = &pas16_proc_info;
394
if (pas16_addr != 0) {
395
overrides[0].io_port = pas16_addr;
397
* This is how we avoid seeing more than
398
* one host adapter at the same I/O port.
399
* Cribbed shamelessly from pas16_setup().
401
for (count = 0; count < NO_BASES; ++count)
402
if (bases[count].io_port == pas16_addr) {
403
bases[count].noauto = 1;
408
overrides[0].irq = pas16_irq;
410
for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
413
if (overrides[current_override].io_port)
415
io_port = overrides[current_override].io_port;
416
enable_board( current_override, io_port );
417
init_board( io_port, overrides[current_override].irq, 1 );
420
for (; !io_port && (current_base < NO_BASES); ++current_base) {
421
#if (PDEBUG & PDEBUG_INIT)
422
printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port);
424
if ( !bases[current_base].noauto &&
425
pas16_hw_detect( current_base ) ){
426
io_port = bases[current_base].io_port;
427
init_board( io_port, default_irqs[ current_base ], 0 );
428
#if (PDEBUG & PDEBUG_INIT)
429
printk("scsi-pas16 : detected board.\n");
435
#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
436
printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port);
442
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
446
instance->io_port = io_port;
448
NCR5380_init(instance, 0);
450
if (overrides[current_override].irq != IRQ_AUTO)
451
instance->irq = overrides[current_override].irq;
453
instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
455
if (instance->irq != SCSI_IRQ_NONE)
456
if (request_irq(instance->irq, pas16_intr, IRQF_DISABLED,
457
"pas16", instance)) {
458
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
459
instance->host_no, instance->irq);
460
instance->irq = SCSI_IRQ_NONE;
463
if (instance->irq == SCSI_IRQ_NONE) {
464
printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
465
printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
466
/* Disable 5380 interrupts, leave drive params the same */
467
outb( 0x4d, io_port + SYS_CONFIG_4 );
468
outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
471
#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
472
printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
475
printk("scsi%d : at 0x%04x", instance->host_no, (int)
477
if (instance->irq == SCSI_IRQ_NONE)
478
printk (" interrupts disabled");
480
printk (" irq %d", instance->irq);
481
printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
482
CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE);
483
NCR5380_print_options(instance);
493
* Function : int pas16_biosparam(Disk *disk, struct block_device *dev, int *ip)
495
* Purpose : Generates a BIOS / DOS compatible H-C-S mapping for
496
* the specified device / size.
498
* Inputs : size = size of device in sectors (512 bytes), dev = block device
499
* major / minor, ip[] = {heads, sectors, cylinders}
501
* Returns : always 0 (success), initializes ip
506
* XXX Most SCSI boards use this mapping, I could be incorrect. Some one
507
* using hard disks on a trantor should verify that this mapping corresponds
508
* to that used by the BIOS / ASPI driver by running the linux fdisk program
509
* and matching the H_C_S coordinates to what DOS uses.
512
int pas16_biosparam(struct scsi_device *sdev, struct block_device *dev,
513
sector_t capacity, int * ip)
518
ip[2] = size >> 11; /* I think I have it as /(32*64) */
519
if( ip[2] > 1024 ) { /* yes, >, not >= */
523
if( ip[2] > 1023 ) /* yes >1023... */
531
* Function : int NCR5380_pread (struct Scsi_Host *instance,
532
* unsigned char *dst, int len)
534
* Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to
537
* Inputs : dst = destination, len = length in bytes
539
* Returns : 0 on success, non zero on a failure such as a watchdog
543
static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
545
register unsigned char *d = dst;
546
register unsigned short reg = (unsigned short) (instance->io_port +
548
register int i = len;
551
while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) )
556
if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
557
outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
558
printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
568
* Function : int NCR5380_pwrite (struct Scsi_Host *instance,
569
* unsigned char *src, int len)
571
* Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
574
* Inputs : src = source, len = length in bytes
576
* Returns : 0 on success, non zero on a failure such as a watchdog
580
static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
582
register unsigned char *s = src;
583
register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
584
register int i = len;
587
while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) )
592
if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
593
outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
594
printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
605
static int pas16_release(struct Scsi_Host *shost)
608
free_irq(shost->irq, shost);
610
if (shost->dma_channel != 0xff)
611
free_dma(shost->dma_channel);
612
if (shost->io_port && shost->n_io_port)
613
release_region(shost->io_port, shost->n_io_port);
614
scsi_unregister(shost);
618
static struct scsi_host_template driver_template = {
619
.name = "Pro Audio Spectrum-16 SCSI",
620
.detect = pas16_detect,
621
.release = pas16_release,
622
.queuecommand = pas16_queue_command,
623
.eh_abort_handler = pas16_abort,
624
.eh_bus_reset_handler = pas16_bus_reset,
625
.bios_param = pas16_biosparam,
626
.can_queue = CAN_QUEUE,
628
.sg_tablesize = SG_ALL,
629
.cmd_per_lun = CMD_PER_LUN,
630
.use_clustering = DISABLE_CLUSTERING,
632
#include "scsi_module.c"
635
module_param(pas16_addr, ushort, 0);
636
module_param(pas16_irq, int, 0);
638
MODULE_LICENSE("GPL");