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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [scsi/] [qlogicfas.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*----------------------------------------------------------------*/
2
/*
3
   Qlogic linux driver - work in progress. No Warranty express or implied.
4
   Use at your own risk.  Support Tort Reform so you won't have to read all
5
   these silly disclaimers.
6
 
7
   Copyright 1994, Tom Zerucha.
8
   tz@execpc.com
9
 
10
   Additional Code, and much appreciated help by
11
   Michael A. Griffith
12
   grif@cs.ucr.edu
13
 
14
   Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
15
   help respectively, and for suffering through my foolishness during the
16
   debugging process.
17
 
18
   Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
19
   (you can reference it, but it is incomplete and inaccurate in places)
20
 
21
   Version 0.46 1/30/97 - kernel 1.2.0+
22
 
23
   Functions as standalone, loadable, and PCMCIA driver, the latter from
24
   Dave Hinds' PCMCIA package.
25
 
26
   Redistributable under terms of the GNU General Public License
27
 
28
*/
29
/*----------------------------------------------------------------*/
30
/* Configuration */
31
 
32
/* Set the following to 2 to use normal interrupt (active high/totempole-
33
   tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
34
   drain */
35
#define QL_INT_ACTIVE_HIGH 2
36
 
37
/* Set the following to 1 to enable the use of interrupts.  Note that 0 tends
38
   to be more stable, but slower (or ties up the system more) */
39
#define QL_USE_IRQ 1
40
 
41
/* Set the following to max out the speed of the PIO PseudoDMA transfers,
42
   again, 0 tends to be slower, but more stable.  */
43
#define QL_TURBO_PDMA 1
44
 
45
/* This should be 1 to enable parity detection */
46
#define QL_ENABLE_PARITY 1
47
 
48
/* This will reset all devices when the driver is initialized (during bootup).
49
   The other linux drivers don't do this, but the DOS drivers do, and after
50
   using DOS or some kind of crash or lockup this will bring things back
51
   without requiring a cold boot.  It does take some time to recover from a
52
   reset, so it is slower, and I have seen timeouts so that devices weren't
53
   recognized when this was set. */
54
#define QL_RESET_AT_START 0
55
 
56
/* crystal frequency in megahertz (for offset 5 and 9)
57
   Please set this for your card.  Most Qlogic cards are 40 Mhz.  The
58
   Control Concepts ISA (not VLB) is 24 Mhz */
59
#define XTALFREQ        40
60
 
61
/**********/
62
/* DANGER! modify these at your own risk */
63
/* SLOWCABLE can usually be reset to zero if you have a clean setup and
64
   proper termination.  The rest are for synchronous transfers and other
65
   advanced features if your device can transfer faster than 5Mb/sec.
66
   If you are really curious, email me for a quick howto until I have
67
   something official */
68
/**********/
69
 
70
/*****/
71
/* config register 1 (offset 8) options */
72
/* This needs to be set to 1 if your cabling is long or noisy */
73
#define SLOWCABLE 1
74
 
75
/*****/
76
/* offset 0xc */
77
/* This will set fast (10Mhz) synchronous timing when set to 1
78
   For this to have an effect, FASTCLK must also be 1 */
79
#define FASTSCSI 0
80
 
81
/* This when set to 1 will set a faster sync transfer rate */
82
#define FASTCLK 0
83
/*(XTALFREQ>25?1:0)*/
84
 
85
/*****/
86
/* offset 6 */
87
/* This is the sync transfer divisor, XTALFREQ/X will be the maximum
88
   achievable data rate (assuming the rest of the system is capable
89
   and set properly) */
90
#define SYNCXFRPD 5
91
/*(XTALFREQ/5)*/
92
 
93
/*****/
94
/* offset 7 */
95
/* This is the count of how many synchronous transfers can take place
96
        i.e. how many reqs can occur before an ack is given.
97
        The maximum value for this is 15, the upper bits can modify
98
        REQ/ACK assertion and deassertion during synchronous transfers
99
        If this is 0, the bus will only transfer asynchronously */
100
#define SYNCOFFST 0
101
/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
102
        of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
103
        cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
104
        the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
105
 
106
/*----------------------------------------------------------------*/
107
#ifdef PCMCIA
108
#undef QL_INT_ACTIVE_HIGH
109
#define QL_INT_ACTIVE_HIGH 0
110
#endif 
111
 
112
#include <linux/module.h>
113
 
114
#include <linux/blk.h>  /* to get disk capacity */
115
#include <linux/kernel.h>
116
#include <linux/string.h>
117
#include <linux/init.h>
118
#include <linux/ioport.h>
119
#include <linux/sched.h>
120
#include <linux/proc_fs.h>
121
#include <linux/unistd.h>
122
#include <linux/spinlock.h>
123
#include <asm/io.h>
124
#include <asm/irq.h>
125
#include "sd.h"
126
#include "hosts.h"
127
#include "qlogicfas.h"
128
#include <linux/stat.h>
129
 
130
#ifdef PCMCIA
131
#undef MODULE
132
#endif 
133
 
134
/*----------------------------------------------------------------*/
135
/* driver state info, local to driver */
136
static int          qbase;      /* Port */
137
static int          qinitid;    /* initiator ID */
138
static int          qabort;     /* Flag to cause an abort */
139
static int          qlirq = -1; /* IRQ being used */
140
static char         qinfo[80];  /* description */
141
static Scsi_Cmnd   *qlcmd;      /* current command being processed */
142
 
143
static int          qlcfg5 = ( XTALFREQ << 5 ); /* 15625/512 */
144
static int          qlcfg6 = SYNCXFRPD;
145
static int          qlcfg7 = SYNCOFFST;
146
static int          qlcfg8 = ( SLOWCABLE << 7 ) | ( QL_ENABLE_PARITY << 4 );
147
static int          qlcfg9 = ( ( XTALFREQ + 4 ) / 5 );
148
static int          qlcfgc = ( FASTCLK << 3 ) | ( FASTSCSI << 4 );
149
 
150
struct  Scsi_Host       *hreg;  /* registered host structure */
151
 
152
/*----------------------------------------------------------------*/
153
/* The qlogic card uses two register maps - These macros select which one */
154
#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
155
#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
156
 
157
/* following is watchdog timeout in microseconds */
158
#define WATCHDOG 5000000
159
 
160
/*----------------------------------------------------------------*/
161
/* the following will set the monitor border color (useful to find
162
   where something crashed or gets stuck at and as a simple profiler) */
163
 
164
#if 0
165
#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
166
#else
167
#define rtrc(i) {}
168
#endif
169
 
170
/*----------------------------------------------------------------*/
171
/* local functions */
172
/*----------------------------------------------------------------*/
173
static void     ql_zap(void);
174
/* error recovery - reset everything */
175
void    ql_zap()
176
{
177
int     x;
178
unsigned long   flags;
179
        save_flags( flags );
180
        cli();
181
        x = inb(qbase + 0xd);
182
        REG0;
183
        outb(3, qbase + 3);                             /* reset SCSI */
184
        outb(2, qbase + 3);                             /* reset chip */
185
        if (x & 0x80)
186
                REG1;
187
        restore_flags( flags );
188
}
189
 
190
/*----------------------------------------------------------------*/
191
/* do pseudo-dma */
192
static int      ql_pdma(int phase, char *request, int reqlen)
193
{
194
int     j;
195
        j = 0;
196
        if (phase & 1) {        /* in */
197
#if QL_TURBO_PDMA
198
rtrc(4)
199
                /* empty fifo in large chunks */
200
                if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) { /* full */
201
                        insl( qbase + 4, request, 32 );
202
                        reqlen -= 128;
203
                        request += 128;
204
                }
205
                while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */
206
                        if( (j=inb( qbase + 8 )) & 4 ) {
207
                                insl( qbase + 4, request, 21 );
208
                                reqlen -= 84;
209
                                request += 84;
210
                        }
211
                if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) {  /* 1/3 */
212
                        insl( qbase + 4, request, 11 );
213
                        reqlen -= 44;
214
                        request += 44;
215
                }
216
#endif
217
                /* until both empty and int (or until reclen is 0) */
218
rtrc(7)
219
                j = 0;
220
                while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) {
221
                        /* while bytes to receive and not empty */
222
                        j &= 0xc0;
223
                        while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) {
224
                                *request++ = inb(qbase + 4);
225
                                reqlen--;
226
                        }
227
                        if( j & 0x10 )
228
                                j = inb(qbase+8);
229
 
230
                }
231
        }
232
        else {  /* out */
233
#if QL_TURBO_PDMA
234
rtrc(4)
235
                if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) { /* empty */
236
                        outsl(qbase + 4, request, 32 );
237
                        reqlen -= 128;
238
                        request += 128;
239
                }
240
                while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */
241
                        if( !((j=inb( qbase + 8 )) & 8) ) {
242
                                outsl( qbase + 4, request, 21 );
243
                                reqlen -= 84;
244
                                request += 84;
245
                        }
246
                if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) { /* 2/3 */
247
                        outsl( qbase + 4, request, 10 );
248
                        reqlen -= 40;
249
                        request += 40;
250
                }
251
#endif
252
                /* until full and int (or until reclen is 0) */
253
rtrc(7)
254
                j = 0;
255
                while( reqlen && !( (j & 2) && (j & 0xc0) ) ) {
256
                        /* while bytes to send and not full */
257
                        while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) {
258
                                outb(*request++, qbase + 4);
259
                                reqlen--;
260
                        }
261
                        if( j & 2 )
262
                                j = inb(qbase+8);
263
                }
264
        }
265
/* maybe return reqlen */
266
        return inb( qbase + 8 ) & 0xc0;
267
}
268
 
269
/*----------------------------------------------------------------*/
270
/* wait for interrupt flag (polled - not real hardware interrupt) */
271
static int      ql_wai(void)
272
{
273
int     i,k;
274
        k = 0;
275
        i = jiffies + WATCHDOG;
276
        while (time_before(jiffies, i) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) {
277
                barrier();
278
                cpu_relax();
279
        }
280
        if (time_after_eq(jiffies, i))
281
                return (DID_TIME_OUT);
282
        if (qabort)
283
                return (qabort == 1 ? DID_ABORT : DID_RESET);
284
        if (k & 0x60)
285
                ql_zap();
286
        if (k & 0x20)
287
                return (DID_PARITY);
288
        if (k & 0x40)
289
                return (DID_ERROR);
290
        return 0;
291
}
292
 
293
/*----------------------------------------------------------------*/
294
/* initiate scsi command - queueing handler */
295
static void     ql_icmd(Scsi_Cmnd * cmd)
296
{
297
unsigned int        i;
298
unsigned long   flags;
299
 
300
        qabort = 0;
301
 
302
        save_flags( flags );
303
        cli();
304
        REG0;
305
/* clearing of interrupts and the fifo is needed */
306
        inb(qbase + 5);                         /* clear interrupts */
307
        if (inb(qbase + 5))                     /* if still interrupting */
308
                outb(2, qbase + 3);             /* reset chip */
309
        else if (inb(qbase + 7) & 0x1f)
310
                outb(1, qbase + 3);             /* clear fifo */
311
        while (inb(qbase + 5));                 /* clear ints */
312
        REG1;
313
        outb(1, qbase + 8);                     /* set for PIO pseudo DMA */
314
        outb(0, qbase + 0xb);                    /* disable ints */
315
        inb(qbase + 8);                         /* clear int bits */
316
        REG0;
317
        outb(0x40, qbase + 0xb);                /* enable features */
318
 
319
/* configurables */
320
        outb( qlcfgc , qbase + 0xc);
321
/* config: no reset interrupt, (initiator) bus id */
322
        outb( 0x40 | qlcfg8 | qinitid, qbase + 8);
323
        outb( qlcfg7 , qbase + 7 );
324
        outb( qlcfg6 , qbase + 6 );
325
/**/
326
        outb(qlcfg5, qbase + 5);                /* select timer */
327
        outb(qlcfg9 & 7, qbase + 9);                    /* prescaler */
328
/*      outb(0x99, qbase + 5);  */
329
        outb(cmd->target, qbase + 4);
330
 
331
        for (i = 0; i < cmd->cmd_len; i++)
332
                outb(cmd->cmnd[i], qbase + 2);
333
        qlcmd = cmd;
334
        outb(0x41, qbase + 3);  /* select and send command */
335
        restore_flags( flags );
336
}
337
/*----------------------------------------------------------------*/
338
/* process scsi command - usually after interrupt */
339
static unsigned int     ql_pcmd(Scsi_Cmnd * cmd)
340
{
341
unsigned int    i, j, k;
342
unsigned int    result;                 /* ultimate return result */
343
unsigned int    status;                 /* scsi returned status */
344
unsigned int    message;                /* scsi returned message */
345
unsigned int    phase;                  /* recorded scsi phase */
346
unsigned int    reqlen;                 /* total length of transfer */
347
struct scatterlist      *sglist;        /* scatter-gather list pointer */
348
unsigned int    sgcount;                /* sg counter */
349
 
350
rtrc(1)
351
        j = inb(qbase + 6);
352
        i = inb(qbase + 5);
353
        if (i == 0x20) {
354
                return (DID_NO_CONNECT << 16);
355
        }
356
        i |= inb(qbase + 5);    /* the 0x10 bit can be set after the 0x08 */
357
        if (i != 0x18) {
358
                printk("Ql:Bad Interrupt status:%02x\n", i);
359
                ql_zap();
360
                return (DID_BAD_INTR << 16);
361
        }
362
        j &= 7; /* j = inb( qbase + 7 ) >> 5; */
363
/* correct status is supposed to be step 4 */
364
/* it sometimes returns step 3 but with 0 bytes left to send */
365
/* We can try stuffing the FIFO with the max each time, but we will get a
366
   sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
367
        if(j != 3 && j != 4) {
368
                printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f );
369
                ql_zap();
370
                return (DID_ERROR << 16);
371
        }
372
        result = DID_OK;
373
        if (inb(qbase + 7) & 0x1f)      /* if some bytes in fifo */
374
                outb(1, qbase + 3);             /* clear fifo */
375
/* note that request_bufflen is the total xfer size when sg is used */
376
        reqlen = cmd->request_bufflen;
377
/* note that it won't work if transfers > 16M are requested */
378
        if (reqlen && !((phase = inb(qbase + 4)) & 6)) {        /* data phase */
379
rtrc(2)
380
                outb(reqlen, qbase);                    /* low-mid xfer cnt */
381
                outb(reqlen >> 8, qbase+1);                     /* low-mid xfer cnt */
382
                outb(reqlen >> 16, qbase + 0xe);        /* high xfer cnt */
383
                outb(0x90, qbase + 3);                  /* command do xfer */
384
/* PIO pseudo DMA to buffer or sglist */
385
                REG1;
386
                if (!cmd->use_sg)
387
                        ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen);
388
                else {
389
                        sgcount = cmd->use_sg;
390
                        sglist = cmd->request_buffer;
391
                        while (sgcount--) {
392
                                if (qabort) {
393
                                        REG0;
394
                                        return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
395
                                }
396
                                if (ql_pdma(phase, sglist->address, sglist->length))
397
                                        break;
398
                                sglist++;
399
                        }
400
                }
401
                REG0;
402
rtrc(2)
403
/* wait for irq (split into second state of irq handler if this can take time) */
404
                if ((k = ql_wai()))
405
                        return (k << 16);
406
                k = inb(qbase + 5);     /* should be 0x10, bus service */
407
        }
408
/*** Enter Status (and Message In) Phase ***/
409
        k = jiffies + WATCHDOG;
410
        while ( time_before(jiffies, k) && !qabort && !(inb(qbase + 4) & 6));   /* wait for status phase */
411
        if ( time_after_eq(jiffies, k) ) {
412
                ql_zap();
413
                return (DID_TIME_OUT << 16);
414
        }
415
        while (inb(qbase + 5));                                 /* clear pending ints */
416
        if (qabort)
417
                return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
418
        outb(0x11, qbase + 3);                                  /* get status and message */
419
        if ((k = ql_wai()))
420
                return (k << 16);
421
        i = inb(qbase + 5);                                     /* get chip irq stat */
422
        j = inb(qbase + 7) & 0x1f;                              /* and bytes rec'd */
423
        status = inb(qbase + 2);
424
        message = inb(qbase + 2);
425
/* should get function complete int if Status and message, else bus serv if only status */
426
        if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
427
                printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
428
                result = DID_ERROR;
429
        }
430
        outb(0x12, qbase + 3);  /* done, disconnect */
431
rtrc(1)
432
        if ((k = ql_wai()))
433
                return (k << 16);
434
/* should get bus service interrupt and disconnect interrupt */
435
        i = inb(qbase + 5);     /* should be bus service */
436
        while (!qabort && ((i & 0x20) != 0x20)) {
437
                barrier();
438
                cpu_relax();
439
                i |= inb(qbase + 5);
440
        }
441
rtrc(0)
442
        if (qabort)
443
                return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
444
        return (result << 16) | (message << 8) | (status & STATUS_MASK);
445
}
446
 
447
#if QL_USE_IRQ
448
/*----------------------------------------------------------------*/
449
/* interrupt handler */
450
static void         ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
451
{
452
Scsi_Cmnd          *icmd;
453
        REG0;
454
        if (!(inb(qbase + 4) & 0x80))   /* false alarm? */
455
                return;
456
        if (qlcmd == NULL) {            /* no command to process? */
457
                int     i;
458
                i = 16;
459
                while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */
460
                return;
461
        }
462
        icmd = qlcmd;
463
        icmd->result = ql_pcmd(icmd);
464
        qlcmd = NULL;
465
/* if result is CHECK CONDITION done calls qcommand to request sense */
466
        (icmd->scsi_done) (icmd);
467
}
468
 
469
static void         do_ql_ihandl(int irq, void *dev_id, struct pt_regs * regs)
470
{
471
        unsigned long flags;
472
 
473
        spin_lock_irqsave(&io_request_lock, flags);
474
        ql_ihandl(irq, dev_id, regs);
475
        spin_unlock_irqrestore(&io_request_lock, flags);
476
}
477
#endif
478
 
479
/*----------------------------------------------------------------*/
480
/* global functions */
481
/*----------------------------------------------------------------*/
482
/* non queued command */
483
#if QL_USE_IRQ
484
static void     qlidone(Scsi_Cmnd * cmd) {};            /* null function */
485
#endif
486
 
487
/* command process */
488
int     qlogicfas_command(Scsi_Cmnd * cmd)
489
{
490
int     k;
491
#if QL_USE_IRQ
492
        if (qlirq >= 0) {
493
                qlogicfas_queuecommand(cmd, qlidone);
494
                while (qlcmd != NULL);
495
                return cmd->result;
496
        }
497
#endif
498
/* non-irq version */
499
        if (cmd->target == qinitid)
500
                return (DID_BAD_TARGET << 16);
501
        ql_icmd(cmd);
502
        if ((k = ql_wai()))
503
                return (k << 16);
504
        return ql_pcmd(cmd);
505
 
506
}
507
 
508
#if QL_USE_IRQ
509
/*----------------------------------------------------------------*/
510
/* queued command */
511
int     qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
512
{
513
        if(cmd->target == qinitid) {
514
                cmd->result = DID_BAD_TARGET << 16;
515
                done(cmd);
516
                return 0;
517
        }
518
 
519
        cmd->scsi_done = done;
520
/* wait for the last command's interrupt to finish */
521
        while (qlcmd != NULL) {
522
                barrier();
523
                cpu_relax();
524
        }
525
        ql_icmd(cmd);
526
        return 0;
527
}
528
#else
529
int     qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
530
{
531
        return 1;
532
}
533
#endif
534
 
535
#ifdef PCMCIA
536
/*----------------------------------------------------------------*/
537
/* allow PCMCIA code to preset the port */
538
/* port should be 0 and irq to -1 respectively for autoprobing */
539
void    qlogicfas_preset(int port, int irq)
540
{
541
        qbase=port;
542
        qlirq=irq;
543
}
544
#endif
545
 
546
int     qlogicfas_release(struct Scsi_Host *hreg)
547
{
548
        release_region(qbase, 0x10);
549
 
550
        if (qlirq >= 0)
551
                free_irq(qlirq, hreg);
552
 
553
        scsi_unregister(hreg);
554
 
555
        return 0;
556
}
557
 
558
/*----------------------------------------------------------------*/
559
/* look for qlogic card and init if found */
560
int __QLINIT qlogicfas_detect(Scsi_Host_Template * host)
561
{
562
int     i, j;                   /* these are only used by IRQ detect */
563
int     qltyp;                  /* type of chip */
564
unsigned long   flags;
565
 
566
host->proc_name =  "qlogicfas";
567
 
568
/* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the
569
   address - I check 230 first since MIDI cards are typically at 330
570
 
571
   Theoretically, two Qlogic cards can coexist in the same system.  This
572
   should work by simply using this as a loadable module for the second
573
   card, but I haven't tested this.
574
*/
575
 
576
        if( !qbase ) {
577
                for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
578
                        if( !request_region( qbase , 0x10, "qlogicfas" ) )
579
                                continue;
580
                        REG1;
581
                        if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
582
                          && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
583
                                break;
584
                        release_region(qbase, 0x10 );
585
                }
586
                if (qbase == 0x430)
587
                        return 0;
588
        }
589
        else
590
                printk( "Ql: Using preset base address of %03x\n", qbase );
591
 
592
        qltyp = inb(qbase + 0xe) & 0xf8;
593
        qinitid = host->this_id;
594
        if (qinitid < 0)
595
                qinitid = 7;                    /* if no ID, use 7 */
596
        outb(1, qbase + 8);                     /* set for PIO pseudo DMA */
597
        REG0;
598
        outb(0x40 | qlcfg8 | qinitid, qbase + 8);       /* (ini) bus id, disable scsi rst */
599
        outb(qlcfg5, qbase + 5);                /* select timer */
600
        outb(qlcfg9, qbase + 9);                        /* prescaler */
601
#if QL_RESET_AT_START
602
        outb( 3 , qbase + 3 );
603
        REG1;
604
        while( inb( qbase + 0xf ) & 4 );
605
        REG0;
606
#endif
607
#if QL_USE_IRQ
608
/* IRQ probe - toggle pin and check request pending */
609
 
610
        if( qlirq == -1 ) {
611
                save_flags( flags );
612
                cli();
613
                i = 0xffff;
614
                j = 3;
615
                outb(0x90, qbase + 3);  /* illegal command - cause interrupt */
616
                REG1;
617
                outb(10, 0x20); /* access pending interrupt map */
618
                outb(10, 0xa0);
619
                while (j--) {
620
                        outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd);  /* int pin off */
621
                        i &= ~(inb(0x20) | (inb(0xa0) << 8));   /* find IRQ off */
622
                        outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd);  /* int pin on */
623
                        i &= inb(0x20) | (inb(0xa0) << 8);      /* find IRQ on */
624
                }
625
                REG0;
626
                while (inb(qbase + 5));                         /* purge int */
627
                j = -1;
628
                while (i)                                       /* find on bit */
629
                        i >>= 1, j++;   /* should check for exactly 1 on */
630
                qlirq = j;
631
                restore_flags( flags );
632
        }
633
        else
634
                printk( "Ql: Using preset IRQ %d\n", qlirq );
635
 
636
        if (qlirq >= 0)
637
                host->can_queue = 1;
638
#endif
639
        hreg = scsi_register( host , 0 );        /* no host data */
640
        if (!hreg)
641
                goto err_release_mem;
642
 
643
#if QL_USE_IRQ
644
#ifdef PCMCIA
645
        if(request_irq(qlirq, do_ql_ihandl, SA_SHIRQ, "qlogicfas", hreg) < 0)
646
#else   
647
        if(request_irq(qlirq, do_ql_ihandl, SA_SHIRQ, "qlogicfas", hreg) < 0)
648
#endif  
649
        {
650
                scsi_unregister(hreg);
651
                goto err_release_mem;
652
        }
653
#endif
654
        hreg->io_port = qbase;
655
        hreg->n_io_port = 16;
656
        hreg->dma_channel = -1;
657
        if( qlirq >= 0 )
658
                hreg->irq = qlirq;
659
 
660
        sprintf(qinfo, "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
661
            qltyp, qbase, qlirq, QL_TURBO_PDMA );
662
        host->name = qinfo;
663
 
664
        return 1;
665
 
666
 err_release_mem:
667
        release_region(qbase, 0x10);
668
        if (qlirq >= 0)
669
                free_irq(qlirq, hreg);
670
        return 0;
671
 
672
}
673
 
674
/*----------------------------------------------------------------*/
675
/* return bios parameters */
676
int     qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[])
677
{
678
/* This should mimic the DOS Qlogic driver's behavior exactly */
679
        ip[0] = 0x40;
680
        ip[1] = 0x20;
681
        ip[2] = disk->capacity / (ip[0] * ip[1]);
682
        if (ip[2] > 1024) {
683
                ip[0] = 0xff;
684
                ip[1] = 0x3f;
685
                ip[2] = disk->capacity / (ip[0] * ip[1]);
686
#if 0
687
                if (ip[2] > 1023)
688
                        ip[2] = 1023;
689
#endif
690
        }
691
        return 0;
692
}
693
 
694
/*----------------------------------------------------------------*/
695
/* abort command in progress */
696
int     qlogicfas_abort(Scsi_Cmnd * cmd)
697
{
698
        qabort = 1;
699
        ql_zap();
700
        return 0;
701
}
702
 
703
/*----------------------------------------------------------------*/
704
/* reset SCSI bus */
705
int     qlogicfas_reset(Scsi_Cmnd * cmd, unsigned int ignored)
706
{
707
        qabort = 2;
708
        ql_zap();
709
        return 1;
710
}
711
 
712
/*----------------------------------------------------------------*/
713
/* return info string */
714
const char      *qlogicfas_info(struct Scsi_Host * host)
715
{
716
        return qinfo;
717
}
718
MODULE_LICENSE("GPL");
719
 
720
#ifndef PCMCIA
721
/* Eventually this will go into an include file, but this will be later */
722
static Scsi_Host_Template driver_template = QLOGICFAS;
723
#include "scsi_module.c"
724
#endif
725
 

powered by: WebSVN 2.1.0

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