1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68#include <linux/module.h>
69
70#include <asm/io.h>
71#include <asm/dma.h>
72#include <linux/blkdev.h>
73#include <linux/interrupt.h>
74#include <linux/init.h>
75
76#include <scsi/scsi_host.h>
77#include "pas16.h"
78#include "NCR5380.h"
79
80
81static unsigned short pas16_addr;
82static int pas16_irq;
83
84
85static const int scsi_irq_translate[] =
86 { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 };
87
88
89
90
91
92
93static int default_irqs[] __initdata =
94 { PAS16_DEFAULT_BOARD_1_IRQ,
95 PAS16_DEFAULT_BOARD_2_IRQ,
96 PAS16_DEFAULT_BOARD_3_IRQ,
97 PAS16_DEFAULT_BOARD_4_IRQ
98 };
99
100static struct override {
101 unsigned short io_port;
102 int irq;
103} overrides
104#ifdef PAS16_OVERRIDE
105 [] __initdata = PAS16_OVERRIDE;
106#else
107 [4] __initdata = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
108 {0,IRQ_AUTO}};
109#endif
110
111#define NO_OVERRIDES ARRAY_SIZE(overrides)
112
113static struct base {
114 unsigned short io_port;
115 int noauto;
116} bases[] __initdata =
117 { {PAS16_DEFAULT_BASE_1, 0},
118 {PAS16_DEFAULT_BASE_2, 0},
119 {PAS16_DEFAULT_BASE_3, 0},
120 {PAS16_DEFAULT_BASE_4, 0}
121 };
122
123#define NO_BASES ARRAY_SIZE(bases)
124
125static const unsigned short pas16_offset[ 8 ] =
126 {
127 0x1c00,
128 0x1c01,
129 0x1c02,
130 0x1c03,
131 0x3c00,
132 0x3c01,
133 0x3c02,
134
135
136 0x3c03,
137
138
139 };
140
141
142
143
144
145
146
147
148
149
150
151static void __init
152 enable_board( int board_num, unsigned short port )
153{
154 outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
155 outb( port >> 2, MASTER_ADDRESS_PTR );
156}
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171static void __init
172 init_board( unsigned short io_port, int irq, int force_irq )
173{
174 unsigned int tmp;
175 unsigned int pas_irq_code;
176
177
178
179 outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG );
180 outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET );
181 outb( 0x01, io_port + WAIT_STATE );
182
183 inb(io_port + pas16_offset[RESET_PARITY_INTERRUPT_REG]);
184
185
186
187
188 pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0;
189 tmp = inb( io_port + IO_CONFIG_3 );
190
191 if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0
192 && !force_irq )
193 {
194 printk( "pas16: WARNING: Can't use same irq as sound "
195 "driver -- interrupts disabled\n" );
196
197 outb( 0x4d, io_port + SYS_CONFIG_4 );
198 }
199 else
200 {
201 tmp = ( tmp & 0x0f ) | ( pas_irq_code << 4 );
202 outb( tmp, io_port + IO_CONFIG_3 );
203
204
205 outb( 0x6d, io_port + SYS_CONFIG_4 );
206 }
207}
208
209
210
211
212
213
214
215
216
217
218
219
220static int __init
221 pas16_hw_detect( unsigned short board_num )
222{
223 unsigned char board_rev, tmp;
224 unsigned short io_port = bases[ board_num ].io_port;
225
226
227
228
229
230
231
232
233 enable_board( board_num, io_port );
234
235
236 board_rev = inb( io_port + PCB_CONFIG );
237
238 if( board_rev == 0xff )
239 return 0;
240
241 tmp = board_rev ^ 0xe0;
242
243 outb( tmp, io_port + PCB_CONFIG );
244 tmp = inb( io_port + PCB_CONFIG );
245 outb( board_rev, io_port + PCB_CONFIG );
246
247 if( board_rev != tmp )
248 return 0;
249
250 if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 )
251 return 0;
252
253
254
255
256
257
258 outb(0x01, io_port + WAIT_STATE);
259 outb(0x20, io_port + pas16_offset[MODE_REG]);
260 if (inb(io_port + pas16_offset[MODE_REG]) != 0x20)
261 return 0;
262 outb(0x00, io_port + pas16_offset[MODE_REG]);
263 if (inb(io_port + pas16_offset[MODE_REG]) != 0x00)
264 return 0;
265
266 return 1;
267}
268
269
270#ifndef MODULE
271
272
273
274
275
276
277
278
279
280
281static int __init pas16_setup(char *str)
282{
283 static int commandline_current;
284 int i;
285 int ints[10];
286
287 get_options(str, ARRAY_SIZE(ints), ints);
288 if (ints[0] != 2)
289 printk("pas16_setup : usage pas16=io_port,irq\n");
290 else
291 if (commandline_current < NO_OVERRIDES) {
292 overrides[commandline_current].io_port = (unsigned short) ints[1];
293 overrides[commandline_current].irq = ints[2];
294 for (i = 0; i < NO_BASES; ++i)
295 if (bases[i].io_port == (unsigned short) ints[1]) {
296 bases[i].noauto = 1;
297 break;
298 }
299 ++commandline_current;
300 }
301 return 1;
302}
303
304__setup("pas16=", pas16_setup);
305#endif
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320static int __init pas16_detect(struct scsi_host_template *tpnt)
321{
322 static int current_override;
323 static unsigned short current_base;
324 struct Scsi_Host *instance;
325 unsigned short io_port;
326 int count;
327
328 if (pas16_addr != 0) {
329 overrides[0].io_port = pas16_addr;
330
331
332
333
334
335 for (count = 0; count < NO_BASES; ++count)
336 if (bases[count].io_port == pas16_addr) {
337 bases[count].noauto = 1;
338 break;
339 }
340 }
341 if (pas16_irq != 0)
342 overrides[0].irq = pas16_irq;
343
344 for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
345 io_port = 0;
346
347 if (overrides[current_override].io_port)
348 {
349 io_port = overrides[current_override].io_port;
350 enable_board( current_override, io_port );
351 init_board( io_port, overrides[current_override].irq, 1 );
352 }
353 else
354 for (; !io_port && (current_base < NO_BASES); ++current_base) {
355 dprintk(NDEBUG_INIT, "pas16: probing io_port 0x%04x\n",
356 (unsigned int)bases[current_base].io_port);
357 if ( !bases[current_base].noauto &&
358 pas16_hw_detect( current_base ) ){
359 io_port = bases[current_base].io_port;
360 init_board( io_port, default_irqs[ current_base ], 0 );
361 dprintk(NDEBUG_INIT, "pas16: detected board\n");
362 }
363 }
364
365 dprintk(NDEBUG_INIT, "pas16: io_port = 0x%04x\n",
366 (unsigned int)io_port);
367
368 if (!io_port)
369 break;
370
371 instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
372 if(instance == NULL)
373 goto out;
374
375 instance->io_port = io_port;
376
377 if (NCR5380_init(instance, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP))
378 goto out_unregister;
379
380 NCR5380_maybe_reset_bus(instance);
381
382 if (overrides[current_override].irq != IRQ_AUTO)
383 instance->irq = overrides[current_override].irq;
384 else
385 instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
386
387
388 if (instance->irq == 255)
389 instance->irq = NO_IRQ;
390
391 if (instance->irq != NO_IRQ)
392 if (request_irq(instance->irq, pas16_intr, 0,
393 "pas16", instance)) {
394 printk("scsi%d : IRQ%d not free, interrupts disabled\n",
395 instance->host_no, instance->irq);
396 instance->irq = NO_IRQ;
397 }
398
399 if (instance->irq == NO_IRQ) {
400 printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
401 printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
402
403 outb( 0x4d, io_port + SYS_CONFIG_4 );
404 outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
405 }
406
407 dprintk(NDEBUG_INIT, "scsi%d : irq = %d\n",
408 instance->host_no, instance->irq);
409
410 ++current_override;
411 ++count;
412 }
413 return count;
414
415out_unregister:
416 scsi_unregister(instance);
417out:
418 return count;
419}
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441static int pas16_biosparam(struct scsi_device *sdev, struct block_device *dev,
442 sector_t capacity, int *ip)
443{
444 int size = capacity;
445 ip[0] = 64;
446 ip[1] = 32;
447 ip[2] = size >> 11;
448 if( ip[2] > 1024 ) {
449 ip[0]=255;
450 ip[1]=63;
451 ip[2]=size/(63*255);
452 if( ip[2] > 1023 )
453 ip[2] = 1023;
454 }
455
456 return 0;
457}
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472static inline int pas16_pread(struct Scsi_Host *instance,
473 unsigned char *dst, int len)
474{
475 register unsigned char *d = dst;
476 register unsigned short reg = (unsigned short) (instance->io_port +
477 P_DATA_REG_OFFSET);
478 register int i = len;
479 int ii = 0;
480
481 while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) )
482 ++ii;
483
484 insb( reg, d, i );
485
486 if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
487 outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
488 printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
489 instance->host_no);
490 return -1;
491 }
492 return 0;
493}
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508static inline int pas16_pwrite(struct Scsi_Host *instance,
509 unsigned char *src, int len)
510{
511 register unsigned char *s = src;
512 register unsigned short reg = (instance->io_port + 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 outsb( reg, s, 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_pwrite()\n",
524 instance->host_no);
525 return -1;
526 }
527 return 0;
528}
529
530#include "NCR5380.c"
531
532static int pas16_release(struct Scsi_Host *shost)
533{
534 if (shost->irq != NO_IRQ)
535 free_irq(shost->irq, shost);
536 NCR5380_exit(shost);
537 scsi_unregister(shost);
538 return 0;
539}
540
541static struct scsi_host_template driver_template = {
542 .name = "Pro Audio Spectrum-16 SCSI",
543 .detect = pas16_detect,
544 .release = pas16_release,
545 .proc_name = "pas16",
546 .info = pas16_info,
547 .queuecommand = pas16_queue_command,
548 .eh_abort_handler = pas16_abort,
549 .eh_bus_reset_handler = pas16_bus_reset,
550 .bios_param = pas16_biosparam,
551 .can_queue = 32,
552 .this_id = 7,
553 .sg_tablesize = SG_ALL,
554 .cmd_per_lun = 2,
555 .use_clustering = DISABLE_CLUSTERING,
556 .cmd_size = NCR5380_CMD_SIZE,
557 .max_sectors = 128,
558};
559#include "scsi_module.c"
560
561#ifdef MODULE
562module_param(pas16_addr, ushort, 0);
563module_param(pas16_irq, int, 0);
564#endif
565MODULE_LICENSE("GPL");
566