ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / scsi / qlogicfas.c
1 /*----------------------------------------------------------------*/
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    Cleaned up 26/10/2002 by Alan Cox <alan@redhat.com> as part of the 2.5
27    SCSI driver cleanup and audit. This driver still needs work on the
28    following
29         -       Non terminating hardware waits
30         -       Some layering violations with its pcmcia stub
31
32    Redistributable under terms of the GNU General Public License
33
34    For the avoidance of doubt the "preferred form" of this code is one which
35    is in an open non patent encumbered format. Where cryptographic key signing
36    forms part of the process of creating an executable the information
37    including keys needed to generate an equivalently functional executable
38    are deemed to be part of the source code.
39
40 */
41
42 #include <linux/module.h>
43 #include <linux/blkdev.h>               /* to get disk capacity */
44 #include <linux/kernel.h>
45 #include <linux/string.h>
46 #include <linux/init.h>
47 #include <linux/interrupt.h>
48 #include <linux/ioport.h>
49 #include <linux/proc_fs.h>
50 #include <linux/unistd.h>
51 #include <linux/spinlock.h>
52 #include <linux/stat.h>
53
54 #include <asm/io.h>
55 #include <asm/irq.h>
56 #include <asm/dma.h>
57
58 #include "scsi.h"
59 #include "hosts.h"
60 #include "qlogicfas.h"
61
62 /*----------------------------------------------------------------*/
63 int qlcfg5 = (XTALFREQ << 5);   /* 15625/512 */
64 int qlcfg6 = SYNCXFRPD;
65 int qlcfg7 = SYNCOFFST;
66 int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
67 int qlcfg9 = ((XTALFREQ + 4) / 5);
68 int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
69
70 static char qlogicfas_name[] = "qlogicfas";
71
72 int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
73
74 /*----------------------------------------------------------------*/
75
76 /*----------------------------------------------------------------*/
77 /* local functions */
78 /*----------------------------------------------------------------*/
79
80 /* error recovery - reset everything */
81
82 static void ql_zap(qlogicfas_priv_t priv)
83 {
84         int x;
85         int qbase = priv->qbase;
86
87         x = inb(qbase + 0xd);
88         REG0;
89         outb(3, qbase + 3);     /* reset SCSI */
90         outb(2, qbase + 3);     /* reset chip */
91         if (x & 0x80)
92                 REG1;
93 }
94
95 /*
96  *      Do a pseudo-dma tranfer
97  */
98  
99 static int ql_pdma(qlogicfas_priv_t priv, int phase, char *request, int reqlen)
100 {
101         int j;
102         int qbase = priv->qbase;
103         j = 0;
104         if (phase & 1) {        /* in */
105 #if QL_TURBO_PDMA
106                 rtrc(4)
107                 /* empty fifo in large chunks */
108                 if (reqlen >= 128 && (inb(qbase + 8) & 2)) {    /* full */
109                         insl(qbase + 4, request, 32);
110                         reqlen -= 128;
111                         request += 128;
112                 }
113                 while (reqlen >= 84 && !(j & 0xc0))     /* 2/3 */
114                         if ((j = inb(qbase + 8)) & 4) 
115                         {
116                                 insl(qbase + 4, request, 21);
117                                 reqlen -= 84;
118                                 request += 84;
119                         }
120                 if (reqlen >= 44 && (inb(qbase + 8) & 8)) {     /* 1/3 */
121                         insl(qbase + 4, request, 11);
122                         reqlen -= 44;
123                         request += 44;
124                 }
125 #endif
126                 /* until both empty and int (or until reclen is 0) */
127                 rtrc(7)
128                 j = 0;
129                 while (reqlen && !((j & 0x10) && (j & 0xc0))) 
130                 {
131                         /* while bytes to receive and not empty */
132                         j &= 0xc0;
133                         while (reqlen && !((j = inb(qbase + 8)) & 0x10)) 
134                         {
135                                 *request++ = inb(qbase + 4);
136                                 reqlen--;
137                         }
138                         if (j & 0x10)
139                                 j = inb(qbase + 8);
140
141                 }
142         } else {                /* out */
143 #if QL_TURBO_PDMA
144                 rtrc(4)
145                     if (reqlen >= 128 && inb(qbase + 8) & 0x10) {       /* empty */
146                         outsl(qbase + 4, request, 32);
147                         reqlen -= 128;
148                         request += 128;
149                 }
150                 while (reqlen >= 84 && !(j & 0xc0))     /* 1/3 */
151                         if (!((j = inb(qbase + 8)) & 8)) {
152                                 outsl(qbase + 4, request, 21);
153                                 reqlen -= 84;
154                                 request += 84;
155                         }
156                 if (reqlen >= 40 && !(inb(qbase + 8) & 4)) {    /* 2/3 */
157                         outsl(qbase + 4, request, 10);
158                         reqlen -= 40;
159                         request += 40;
160                 }
161 #endif
162                 /* until full and int (or until reclen is 0) */
163                 rtrc(7)
164                     j = 0;
165                 while (reqlen && !((j & 2) && (j & 0xc0))) {
166                         /* while bytes to send and not full */
167                         while (reqlen && !((j = inb(qbase + 8)) & 2)) 
168                         {
169                                 outb(*request++, qbase + 4);
170                                 reqlen--;
171                         }
172                         if (j & 2)
173                                 j = inb(qbase + 8);
174                 }
175         }
176         /* maybe return reqlen */
177         return inb(qbase + 8) & 0xc0;
178 }
179
180 /*
181  *      Wait for interrupt flag (polled - not real hardware interrupt) 
182  */
183
184 static int ql_wai(qlogicfas_priv_t priv)
185 {
186         int k;
187         int qbase = priv->qbase;
188         unsigned long i;
189
190         k = 0;
191         i = jiffies + WATCHDOG;
192         while (time_before(jiffies, i) && !priv->qabort &&
193                                         !((k = inb(qbase + 4)) & 0xe0)) {
194                 barrier();
195                 cpu_relax();
196         }
197         if (time_after_eq(jiffies, i))
198                 return (DID_TIME_OUT);
199         if (priv->qabort)
200                 return (priv->qabort == 1 ? DID_ABORT : DID_RESET);
201         if (k & 0x60)
202                 ql_zap(priv);
203         if (k & 0x20)
204                 return (DID_PARITY);
205         if (k & 0x40)
206                 return (DID_ERROR);
207         return 0;
208 }
209
210 /*
211  *      Initiate scsi command - queueing handler 
212  *      caller must hold host lock
213  */
214
215 static void ql_icmd(Scsi_Cmnd * cmd)
216 {
217         qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
218         int     qbase = priv->qbase;
219         unsigned int i;
220
221         priv->qabort = 0;
222
223         REG0;
224         /* clearing of interrupts and the fifo is needed */
225
226         inb(qbase + 5);         /* clear interrupts */
227         if (inb(qbase + 5))     /* if still interrupting */
228                 outb(2, qbase + 3);     /* reset chip */
229         else if (inb(qbase + 7) & 0x1f)
230                 outb(1, qbase + 3);     /* clear fifo */
231         while (inb(qbase + 5)); /* clear ints */
232         REG1;
233         outb(1, qbase + 8);     /* set for PIO pseudo DMA */
234         outb(0, qbase + 0xb);   /* disable ints */
235         inb(qbase + 8);         /* clear int bits */
236         REG0;
237         outb(0x40, qbase + 0xb);        /* enable features */
238
239         /* configurables */
240         outb(qlcfgc, qbase + 0xc);
241         /* config: no reset interrupt, (initiator) bus id */
242         outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
243         outb(qlcfg7, qbase + 7);
244         outb(qlcfg6, qbase + 6);
245          /**/ outb(qlcfg5, qbase + 5);  /* select timer */
246         outb(qlcfg9 & 7, qbase + 9);    /* prescaler */
247 /*      outb(0x99, qbase + 5);  */
248         outb(cmd->device->id, qbase + 4);
249
250         for (i = 0; i < cmd->cmd_len; i++)
251                 outb(cmd->cmnd[i], qbase + 2);
252
253         priv->qlcmd = cmd;
254         outb(0x41, qbase + 3);  /* select and send command */
255 }
256
257 /*
258  *      Process scsi command - usually after interrupt 
259  */
260
261 static unsigned int ql_pcmd(Scsi_Cmnd * cmd)
262 {
263         unsigned int i, j;
264         unsigned long k;
265         unsigned int result;    /* ultimate return result */
266         unsigned int status;    /* scsi returned status */
267         unsigned int message;   /* scsi returned message */
268         unsigned int phase;     /* recorded scsi phase */
269         unsigned int reqlen;    /* total length of transfer */
270         struct scatterlist *sglist;     /* scatter-gather list pointer */
271         unsigned int sgcount;   /* sg counter */
272         char *buf;
273         qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
274         int qbase = priv->qbase;
275
276         rtrc(1)
277         j = inb(qbase + 6);
278         i = inb(qbase + 5);
279         if (i == 0x20) {
280                 return (DID_NO_CONNECT << 16);
281         }
282         i |= inb(qbase + 5);    /* the 0x10 bit can be set after the 0x08 */
283         if (i != 0x18) {
284                 printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
285                 ql_zap(priv);
286                 return (DID_BAD_INTR << 16);
287         }
288         j &= 7;                 /* j = inb( qbase + 7 ) >> 5; */
289
290         /* correct status is supposed to be step 4 */
291         /* it sometimes returns step 3 but with 0 bytes left to send */
292         /* We can try stuffing the FIFO with the max each time, but we will get a
293            sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
294
295         if (j != 3 && j != 4) {
296                 printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n",
297                      j, i, inb(qbase + 7) & 0x1f);
298                 ql_zap(priv);
299                 return (DID_ERROR << 16);
300         }
301         result = DID_OK;
302         if (inb(qbase + 7) & 0x1f)      /* if some bytes in fifo */
303                 outb(1, qbase + 3);     /* clear fifo */
304         /* note that request_bufflen is the total xfer size when sg is used */
305         reqlen = cmd->request_bufflen;
306         /* note that it won't work if transfers > 16M are requested */
307         if (reqlen && !((phase = inb(qbase + 4)) & 6)) {        /* data phase */
308                 rtrc(2)
309                 outb(reqlen, qbase);    /* low-mid xfer cnt */
310                 outb(reqlen >> 8, qbase + 1);   /* low-mid xfer cnt */
311                 outb(reqlen >> 16, qbase + 0xe);        /* high xfer cnt */
312                 outb(0x90, qbase + 3);  /* command do xfer */
313                 /* PIO pseudo DMA to buffer or sglist */
314                 REG1;
315                 if (!cmd->use_sg)
316                         ql_pdma(priv, phase, cmd->request_buffer,
317                                 cmd->request_bufflen);
318                 else {
319                         sgcount = cmd->use_sg;
320                         sglist = cmd->request_buffer;
321                         while (sgcount--) {
322                                 if (priv->qabort) {
323                                         REG0;
324                                         return ((priv->qabort == 1 ?
325                                                 DID_ABORT : DID_RESET) << 16);
326                                 }
327                                 buf = page_address(sglist->page) + sglist->offset;
328                                 if (ql_pdma(priv, phase, buf, sglist->length))
329                                         break;
330                                 sglist++;
331                         }
332                 }
333                 REG0;
334                 rtrc(2)
335                 /*
336                  *      Wait for irq (split into second state of irq handler
337                  *      if this can take time) 
338                  */
339                 if ((k = ql_wai(priv)))
340                         return (k << 16);
341                 k = inb(qbase + 5);     /* should be 0x10, bus service */
342         }
343
344         /*
345          *      Enter Status (and Message In) Phase 
346          */
347          
348         k = jiffies + WATCHDOG;
349
350         while (time_before(jiffies, k) && !priv->qabort &&
351                                                 !(inb(qbase + 4) & 6))
352                 cpu_relax();    /* wait for status phase */
353
354         if (time_after_eq(jiffies, k)) {
355                 ql_zap(priv);
356                 return (DID_TIME_OUT << 16);
357         }
358
359         /* FIXME: timeout ?? */
360         while (inb(qbase + 5))
361                 cpu_relax();    /* clear pending ints */
362
363         if (priv->qabort)
364                 return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
365
366         outb(0x11, qbase + 3);  /* get status and message */
367         if ((k = ql_wai(priv)))
368                 return (k << 16);
369         i = inb(qbase + 5);     /* get chip irq stat */
370         j = inb(qbase + 7) & 0x1f;      /* and bytes rec'd */
371         status = inb(qbase + 2);
372         message = inb(qbase + 2);
373
374         /*
375          *      Should get function complete int if Status and message, else 
376          *      bus serv if only status 
377          */
378         if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
379                 printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
380                 result = DID_ERROR;
381         }
382         outb(0x12, qbase + 3);  /* done, disconnect */
383         rtrc(1)
384         if ((k = ql_wai(priv)))
385                 return (k << 16);
386
387         /*
388          *      Should get bus service interrupt and disconnect interrupt 
389          */
390          
391         i = inb(qbase + 5);     /* should be bus service */
392         while (!priv->qabort && ((i & 0x20) != 0x20)) {
393                 barrier();
394                 cpu_relax();
395                 i |= inb(qbase + 5);
396         }
397         rtrc(0)
398
399         if (priv->qabort)
400                 return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
401                 
402         return (result << 16) | (message << 8) | (status & STATUS_MASK);
403 }
404
405 /*
406  *      Interrupt handler 
407  */
408
409 static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
410 {
411         Scsi_Cmnd *icmd;
412         struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
413         qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]);
414         int qbase = priv->qbase;
415         REG0;
416
417         if (!(inb(qbase + 4) & 0x80))   /* false alarm? */
418                 return;
419
420         if (priv->qlcmd == NULL) {      /* no command to process? */
421                 int i;
422                 i = 16;
423                 while (i-- && inb(qbase + 5));  /* maybe also ql_zap() */
424                 return;
425         }
426         icmd = priv->qlcmd;
427         icmd->result = ql_pcmd(icmd);
428         priv->qlcmd = NULL;
429         /*
430          *      If result is CHECK CONDITION done calls qcommand to request 
431          *      sense 
432          */
433         (icmd->scsi_done) (icmd);
434 }
435
436 irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
437 {
438         unsigned long flags;
439         struct Scsi_Host *host = dev_id;
440
441         spin_lock_irqsave(host->host_lock, flags);
442         ql_ihandl(irq, dev_id, regs);
443         spin_unlock_irqrestore(host->host_lock, flags);
444         return IRQ_HANDLED;
445 }
446
447 /*
448  *      Queued command
449  */
450
451 int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
452 {
453         qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
454         if (cmd->device->id == priv->qinitid) {
455                 cmd->result = DID_BAD_TARGET << 16;
456                 done(cmd);
457                 return 0;
458         }
459
460         cmd->scsi_done = done;
461         /* wait for the last command's interrupt to finish */
462         while (priv->qlcmd != NULL) {
463                 barrier();
464                 cpu_relax();
465         }
466         ql_icmd(cmd);
467         return 0;
468 }
469
470 #ifndef PCMCIA
471 /*
472  *      Look for qlogic card and init if found 
473  */
474  
475 struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host, int qbase,
476                                                                 int qlirq)
477 {
478         int i, j;               /* these are only used by IRQ detect */
479         int qltyp;              /* type of chip */
480         int qinitid;
481         struct Scsi_Host *hreg; /* registered host structure */
482         qlogicfas_priv_t priv;
483
484         /*      Qlogic Cards only exist at 0x230 or 0x330 (the chip itself
485          *      decodes the address - I check 230 first since MIDI cards are
486          *      typically at 0x330
487          *
488          *      Theoretically, two Qlogic cards can coexist in the same system.
489          *      This should work by simply using this as a loadable module for
490          *      the second card, but I haven't tested this.
491          */
492
493         if (!qbase) {
494                 for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
495                         if (!request_region(qbase, 0x10, qlogicfas_name))
496                                 continue;
497                         REG1;
498                         if (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7)
499                             && ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7))
500                                 break;
501                         release_region(qbase, 0x10);
502                 }
503                 if (qbase == 0x430)
504                         return NULL;
505         } else
506                 printk(KERN_INFO "Ql: Using preset base address of %03x\n", qbase);
507
508         qltyp = inb(qbase + 0xe) & 0xf8;
509         qinitid = host->this_id;
510         if (qinitid < 0)
511                 qinitid = 7;    /* if no ID, use 7 */
512         outb(1, qbase + 8);     /* set for PIO pseudo DMA */
513         REG0;
514         outb(0x40 | qlcfg8 | qinitid, qbase + 8);       /* (ini) bus id, disable scsi rst */
515         outb(qlcfg5, qbase + 5);        /* select timer */
516         outb(qlcfg9, qbase + 9);        /* prescaler */
517
518 #if QL_RESET_AT_START
519         outb(3, qbase + 3);
520         REG1;
521         /* FIXME: timeout */
522         while (inb(qbase + 0xf) & 4)
523                 cpu_relax();
524         REG0;
525 #endif
526
527         /*
528          *      IRQ probe - toggle pin and check request pending 
529          */
530
531         if (qlirq == -1) {
532                 i = 0xffff;
533                 j = 3;
534                 outb(0x90, qbase + 3);  /* illegal command - cause interrupt */
535                 REG1;
536                 outb(10, 0x20); /* access pending interrupt map */
537                 outb(10, 0xa0);
538                 while (j--) {
539                         outb(0xb0 | QL_INT_ACTIVE_HIGH, qbase + 0xd);   /* int pin off */
540                         i &= ~(inb(0x20) | (inb(0xa0) << 8));           /* find IRQ off */
541                         outb(0xb4 | QL_INT_ACTIVE_HIGH, qbase + 0xd);   /* int pin on */
542                         i &= inb(0x20) | (inb(0xa0) << 8);              /* find IRQ on */
543                 }
544                 REG0;
545                 while (inb(qbase + 5)); /* purge int */
546                 j = -1;
547                 while (i)       /* find on bit */
548                         i >>= 1, j++;   /* should check for exactly 1 on */
549                 qlirq = j;
550         } else
551                 printk(KERN_INFO "Ql: Using preset IRQ %d\n", qlirq);
552
553         hreg = scsi_host_alloc(host, sizeof(struct qlogicfas_priv));
554         if (!hreg)
555                 goto err_release_mem;
556         priv = (qlogicfas_priv_t)&(hreg->hostdata[0]);
557         hreg->io_port = qbase;
558         hreg->n_io_port = 16;
559         hreg->dma_channel = -1;
560         if (qlirq != -1)
561                 hreg->irq = qlirq;
562         priv->qbase = qbase;
563         priv->qlirq = qlirq;
564         priv->qinitid = qinitid;
565         priv->shost = hreg;
566
567         sprintf(priv->qinfo,
568                 "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
569                 qltyp, qbase, qlirq, QL_TURBO_PDMA);
570         host->name = qlogicfas_name;
571
572         if (request_irq(qlirq, do_ql_ihandl, 0, qlogicfas_name, hreg))
573                 goto free_scsi_host;
574
575         if (scsi_add_host(hreg, NULL))
576                 goto free_interrupt;
577
578         scsi_scan_host(hreg);
579
580         return hreg;
581
582 free_interrupt:
583         free_irq(qlirq, hreg);
584
585 free_scsi_host:
586         scsi_host_put(hreg);
587
588 err_release_mem:
589         release_region(qbase, 0x10);
590         return NULL;
591 }
592
593 #define MAX_QLOGICFAS   8
594 static qlogicfas_priv_t cards;
595 static int iobase[MAX_QLOGICFAS];
596 static int irq[MAX_QLOGICFAS] = { [0 ... MAX_QLOGICFAS-1] = -1 };
597 MODULE_PARM(iobase, "1-" __MODULE_STRING(MAX_QLOGICFAS) "i");
598 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_QLOGICFAS) "i");
599 MODULE_PARM_DESC(iobase, "I/O address");
600 MODULE_PARM_DESC(irq, "IRQ");
601
602 int __devinit qlogicfas_detect(Scsi_Host_Template *sht)
603 {
604         struct Scsi_Host        *shost;
605         qlogicfas_priv_t        priv;
606         int     i,
607                 num = 0;
608
609         for (i = 0; i < MAX_QLOGICFAS; i++) {
610                 shost = __qlogicfas_detect(sht, iobase[num], irq[num]);
611                 if (shost == NULL) {
612                         /* no more devices */
613                         break;
614                 }
615                 priv = (qlogicfas_priv_t)&(shost->hostdata[0]);
616                 priv->next = cards;
617                 cards = priv;
618                 num++;
619         }
620
621         return num;
622 }
623
624 static int qlogicfas_release(struct Scsi_Host *shost)
625 {
626         qlogicfas_priv_t priv = (qlogicfas_priv_t)&(shost->hostdata[0]);
627         int qbase = priv->qbase;
628
629         if (shost->irq) {
630                 REG1;
631                 outb(0, qbase + 0xb);   /* disable ints */
632         
633                 free_irq(shost->irq, shost);
634         }
635         if (shost->dma_channel != 0xff)
636                 free_dma(shost->dma_channel);
637         if (shost->io_port && shost->n_io_port)
638                 release_region(shost->io_port, shost->n_io_port);
639         scsi_remove_host(shost);
640         scsi_host_put(shost);
641
642         return 0;
643 }
644 #endif  /* ifndef PCMCIA */
645
646 /* 
647  *      Return bios parameters 
648  */
649
650 int qlogicfas_biosparam(struct scsi_device * disk,
651                         struct block_device *dev,
652                         sector_t capacity, int ip[])
653 {
654 /* This should mimic the DOS Qlogic driver's behavior exactly */
655         ip[0] = 0x40;
656         ip[1] = 0x20;
657         ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
658         if (ip[2] > 1024) {
659                 ip[0] = 0xff;
660                 ip[1] = 0x3f;
661                 ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
662 #if 0
663                 if (ip[2] > 1023)
664                         ip[2] = 1023;
665 #endif
666         }
667         return 0;
668 }
669
670 /*
671  *      Abort a command in progress
672  */
673  
674 static int qlogicfas_abort(Scsi_Cmnd * cmd)
675 {
676         qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
677         priv->qabort = 1;
678         ql_zap(priv);
679         return SUCCESS;
680 }
681
682 /* 
683  *      Reset SCSI bus
684  *      FIXME: This function is invoked with cmd = NULL directly by
685  *      the PCMCIA qlogic_stub code. This wants fixing
686  */
687
688 int qlogicfas_bus_reset(Scsi_Cmnd * cmd)
689 {
690         qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]);
691         priv->qabort = 2;
692         ql_zap(priv);
693         return SUCCESS;
694 }
695
696 /* 
697  *      Reset SCSI host controller
698  */
699
700 static int qlogicfas_host_reset(Scsi_Cmnd * cmd)
701 {
702         return FAILED;
703 }
704
705 /* 
706  *      Reset SCSI device
707  */
708
709 static int qlogicfas_device_reset(Scsi_Cmnd * cmd)
710 {
711         return FAILED;
712 }
713
714 /*
715  *      Return info string
716  */
717
718 static const char *qlogicfas_info(struct Scsi_Host *host)
719 {
720         qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]);
721         return priv->qinfo;
722 }
723
724 /*
725  *      The driver template is also needed for PCMCIA
726  */
727 Scsi_Host_Template qlogicfas_driver_template = {
728         .module                 = THIS_MODULE,
729         .name                   = qlogicfas_name,
730         .proc_name              = qlogicfas_name,
731         .info                   = qlogicfas_info,
732         .queuecommand           = qlogicfas_queuecommand,
733         .eh_abort_handler       = qlogicfas_abort,
734         .eh_bus_reset_handler   = qlogicfas_bus_reset,
735         .eh_device_reset_handler= qlogicfas_device_reset,
736         .eh_host_reset_handler  = qlogicfas_host_reset,
737         .bios_param             = qlogicfas_biosparam,
738         .can_queue              = 1,
739         .this_id                = -1,
740         .sg_tablesize           = SG_ALL,
741         .cmd_per_lun            = 1,
742         .use_clustering         = DISABLE_CLUSTERING,
743 };
744
745 #ifndef PCMCIA
746 static __init int qlogicfas_init(void)
747 {
748         if (!qlogicfas_detect(&qlogicfas_driver_template)) {
749                 /* no cards found */
750                 return -ENODEV;
751         }
752
753         return 0;
754 }
755
756 static __exit void qlogicfas_exit(void)
757 {
758         qlogicfas_priv_t        priv;
759
760         for (priv = cards; priv != NULL; priv = priv->next)
761                 qlogicfas_release(priv->shost);
762 }
763
764 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
765 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
766 MODULE_LICENSE("GPL");
767 module_init(qlogicfas_init);
768 module_exit(qlogicfas_exit);
769 #endif  /* ifndef PCMCIA */
770