GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / scsi / qlogicfas408.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@lxorguk.ukuu.org.uk> 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/scsi.h>
59 #include <scsi/scsi_cmnd.h>
60 #include <scsi/scsi_device.h>
61 #include <scsi/scsi_eh.h>
62 #include <scsi/scsi_host.h>
63 #include <scsi/scsi_tcq.h>
64 #include "qlogicfas408.h"
65
66 /*----------------------------------------------------------------*/
67 static int qlcfg5 = (XTALFREQ << 5);    /* 15625/512 */
68 static int qlcfg6 = SYNCXFRPD;
69 static int qlcfg7 = SYNCOFFST;
70 static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
71 static int qlcfg9 = ((XTALFREQ + 4) / 5);
72 static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
73
74 /*----------------------------------------------------------------*/
75
76 /*----------------------------------------------------------------*/
77 /* local functions */
78 /*----------------------------------------------------------------*/
79
80 /* error recovery - reset everything */
81
82 static void ql_zap(struct qlogicfas408_priv *priv)
83 {
84         int x;
85         int qbase = priv->qbase;
86         int int_type = priv->int_type;
87
88         x = inb(qbase + 0xd);
89         REG0;
90         outb(3, qbase + 3);     /* reset SCSI */
91         outb(2, qbase + 3);     /* reset chip */
92         if (x & 0x80)
93                 REG1;
94 }
95
96 /*
97  *      Do a pseudo-dma tranfer
98  */
99
100 static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request,
101                    int reqlen)
102 {
103         int j;
104         int qbase = priv->qbase;
105         j = 0;
106         if (phase & 1) {        /* in */
107 #if QL_TURBO_PDMA
108                 rtrc(4)
109                 /* empty fifo in large chunks */
110                 if (reqlen >= 128 && (inb(qbase + 8) & 2)) {    /* full */
111                         insl(qbase + 4, request, 32);
112                         reqlen -= 128;
113                         request += 128;
114                 }
115                 while (reqlen >= 84 && !(j & 0xc0))     /* 2/3 */
116                         if ((j = inb(qbase + 8)) & 4)
117                         {
118                                 insl(qbase + 4, request, 21);
119                                 reqlen -= 84;
120                                 request += 84;
121                         }
122                 if (reqlen >= 44 && (inb(qbase + 8) & 8)) {     /* 1/3 */
123                         insl(qbase + 4, request, 11);
124                         reqlen -= 44;
125                         request += 44;
126                 }
127 #endif
128                 /* until both empty and int (or until reclen is 0) */
129                 rtrc(7)
130                 j = 0;
131                 while (reqlen && !((j & 0x10) && (j & 0xc0)))
132                 {
133                         /* while bytes to receive and not empty */
134                         j &= 0xc0;
135                         while (reqlen && !((j = inb(qbase + 8)) & 0x10))
136                         {
137                                 *request++ = inb(qbase + 4);
138                                 reqlen--;
139                         }
140                         if (j & 0x10)
141                                 j = inb(qbase + 8);
142
143                 }
144         } else {                /* out */
145 #if QL_TURBO_PDMA
146                 rtrc(4)
147                 if (reqlen >= 128 && inb(qbase + 8) & 0x10) {   /* empty */
148                         outsl(qbase + 4, request, 32);
149                         reqlen -= 128;
150                         request += 128;
151                 }
152                 while (reqlen >= 84 && !(j & 0xc0))     /* 1/3 */
153                         if (!((j = inb(qbase + 8)) & 8)) {
154                                 outsl(qbase + 4, request, 21);
155                                 reqlen -= 84;
156                                 request += 84;
157                         }
158                 if (reqlen >= 40 && !(inb(qbase + 8) & 4)) {    /* 2/3 */
159                         outsl(qbase + 4, request, 10);
160                         reqlen -= 40;
161                         request += 40;
162                 }
163 #endif
164                 /* until full and int (or until reclen is 0) */
165                 rtrc(7)
166                     j = 0;
167                 while (reqlen && !((j & 2) && (j & 0xc0))) {
168                         /* while bytes to send and not full */
169                         while (reqlen && !((j = inb(qbase + 8)) & 2))
170                         {
171                                 outb(*request++, qbase + 4);
172                                 reqlen--;
173                         }
174                         if (j & 2)
175                                 j = inb(qbase + 8);
176                 }
177         }
178         /* maybe return reqlen */
179         return inb(qbase + 8) & 0xc0;
180 }
181
182 /*
183  *      Wait for interrupt flag (polled - not real hardware interrupt)
184  */
185
186 static int ql_wai(struct qlogicfas408_priv *priv)
187 {
188         int k;
189         int qbase = priv->qbase;
190         unsigned long i;
191
192         k = 0;
193         i = jiffies + WATCHDOG;
194         while (time_before(jiffies, i) && !priv->qabort &&
195                                         !((k = inb(qbase + 4)) & 0xe0)) {
196                 barrier();
197                 cpu_relax();
198         }
199         if (time_after_eq(jiffies, i))
200                 return (DID_TIME_OUT);
201         if (priv->qabort)
202                 return (priv->qabort == 1 ? DID_ABORT : DID_RESET);
203         if (k & 0x60)
204                 ql_zap(priv);
205         if (k & 0x20)
206                 return (DID_PARITY);
207         if (k & 0x40)
208                 return (DID_ERROR);
209         return 0;
210 }
211
212 /*
213  *      Initiate scsi command - queueing handler
214  *      caller must hold host lock
215  */
216
217 static void ql_icmd(struct scsi_cmnd *cmd)
218 {
219         struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
220         int     qbase = priv->qbase;
221         int     int_type = priv->int_type;
222         unsigned int i;
223
224         priv->qabort = 0;
225
226         REG0;
227         /* clearing of interrupts and the fifo is needed */
228
229         inb(qbase + 5);         /* clear interrupts */
230         if (inb(qbase + 5))     /* if still interrupting */
231                 outb(2, qbase + 3);     /* reset chip */
232         else if (inb(qbase + 7) & 0x1f)
233                 outb(1, qbase + 3);     /* clear fifo */
234         while (inb(qbase + 5)); /* clear ints */
235         REG1;
236         outb(1, qbase + 8);     /* set for PIO pseudo DMA */
237         outb(0, qbase + 0xb);   /* disable ints */
238         inb(qbase + 8);         /* clear int bits */
239         REG0;
240         outb(0x40, qbase + 0xb);        /* enable features */
241
242         /* configurables */
243         outb(qlcfgc, qbase + 0xc);
244         /* config: no reset interrupt, (initiator) bus id */
245         outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
246         outb(qlcfg7, qbase + 7);
247         outb(qlcfg6, qbase + 6);
248         outb(qlcfg5, qbase + 5);        /* select timer */
249         outb(qlcfg9 & 7, qbase + 9);    /* prescaler */
250 /*      outb(0x99, qbase + 5);  */
251         outb(scmd_id(cmd), qbase + 4);
252
253         for (i = 0; i < cmd->cmd_len; i++)
254                 outb(cmd->cmnd[i], qbase + 2);
255
256         priv->qlcmd = cmd;
257         outb(0x41, qbase + 3);  /* select and send command */
258 }
259
260 /*
261  *      Process scsi command - usually after interrupt
262  */
263
264 static void ql_pcmd(struct scsi_cmnd *cmd)
265 {
266         unsigned int i, j;
267         unsigned long k;
268         unsigned int status;    /* scsi returned status */
269         unsigned int message;   /* scsi returned message */
270         unsigned int phase;     /* recorded scsi phase */
271         unsigned int reqlen;    /* total length of transfer */
272         char *buf;
273         struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
274         int qbase = priv->qbase;
275         int int_type = priv->int_type;
276
277         rtrc(1)
278         j = inb(qbase + 6);
279         i = inb(qbase + 5);
280         if (i == 0x20) {
281                 set_host_byte(cmd, DID_NO_CONNECT);
282                 return;
283         }
284         i |= inb(qbase + 5);    /* the 0x10 bit can be set after the 0x08 */
285         if (i != 0x18) {
286                 printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
287                 ql_zap(priv);
288                 set_host_byte(cmd, DID_BAD_INTR);
289                 return;
290         }
291         j &= 7;                 /* j = inb( qbase + 7 ) >> 5; */
292
293         /* correct status is supposed to be step 4 */
294         /* it sometimes returns step 3 but with 0 bytes left to send */
295         /* We can try stuffing the FIFO with the max each time, but we will get a
296            sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
297
298         if (j != 3 && j != 4) {
299                 printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n",
300                      j, i, inb(qbase + 7) & 0x1f);
301                 ql_zap(priv);
302                 set_host_byte(cmd, DID_ERROR);
303                 return;
304         }
305
306         if (inb(qbase + 7) & 0x1f)      /* if some bytes in fifo */
307                 outb(1, qbase + 3);     /* clear fifo */
308         /* note that request_bufflen is the total xfer size when sg is used */
309         reqlen = scsi_bufflen(cmd);
310         /* note that it won't work if transfers > 16M are requested */
311         if (reqlen && !((phase = inb(qbase + 4)) & 6)) {        /* data phase */
312                 struct scatterlist *sg;
313                 rtrc(2)
314                 outb(reqlen, qbase);    /* low-mid xfer cnt */
315                 outb(reqlen >> 8, qbase + 1);   /* low-mid xfer cnt */
316                 outb(reqlen >> 16, qbase + 0xe);        /* high xfer cnt */
317                 outb(0x90, qbase + 3);  /* command do xfer */
318                 /* PIO pseudo DMA to buffer or sglist */
319                 REG1;
320
321                 scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
322                         if (priv->qabort) {
323                                 REG0;
324                                 set_host_byte(cmd,
325                                               priv->qabort == 1 ?
326                                               DID_ABORT : DID_RESET);
327                         }
328                         buf = sg_virt(sg);
329                         if (ql_pdma(priv, phase, buf, sg->length))
330                                 break;
331                 }
332                 REG0;
333                 rtrc(2);
334                 /*
335                  *      Wait for irq (split into second state of irq handler
336                  *      if this can take time)
337                  */
338                 if ((k = ql_wai(priv))) {
339                         set_host_byte(cmd, k);
340                         return;
341                 }
342                 k = inb(qbase + 5);     /* should be 0x10, bus service */
343         }
344
345         /*
346          *      Enter Status (and Message In) Phase
347          */
348
349         k = jiffies + WATCHDOG;
350
351         while (time_before(jiffies, k) && !priv->qabort &&
352                                                 !(inb(qbase + 4) & 6))
353                 cpu_relax();    /* wait for status phase */
354
355         if (time_after_eq(jiffies, k)) {
356                 ql_zap(priv);
357                 set_host_byte(cmd, DID_TIME_OUT);
358                 return;
359         }
360
361         /* FIXME: timeout ?? */
362         while (inb(qbase + 5))
363                 cpu_relax();    /* clear pending ints */
364
365         if (priv->qabort) {
366                 set_host_byte(cmd,
367                               priv->qabort == 1 ? DID_ABORT : DID_RESET);
368                 return;
369         }
370
371         outb(0x11, qbase + 3);  /* get status and message */
372         if ((k = ql_wai(priv))) {
373                 set_host_byte(cmd, k);
374                 return;
375         }
376         i = inb(qbase + 5);     /* get chip irq stat */
377         j = inb(qbase + 7) & 0x1f;      /* and bytes rec'd */
378         status = inb(qbase + 2);
379         message = inb(qbase + 2);
380
381         /*
382          *      Should get function complete int if Status and message, else
383          *      bus serv if only status
384          */
385         if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
386                 printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
387                 set_host_byte(cmd, DID_ERROR);
388         }
389         outb(0x12, qbase + 3);  /* done, disconnect */
390         rtrc(1);
391         if ((k = ql_wai(priv))) {
392                 set_host_byte(cmd, k);
393                 return;
394         }
395
396         /*
397          *      Should get bus service interrupt and disconnect interrupt
398          */
399
400         i = inb(qbase + 5);     /* should be bus service */
401         while (!priv->qabort && ((i & 0x20) != 0x20)) {
402                 barrier();
403                 cpu_relax();
404                 i |= inb(qbase + 5);
405         }
406         rtrc(0);
407
408         if (priv->qabort) {
409                 set_host_byte(cmd,
410                               priv->qabort == 1 ? DID_ABORT : DID_RESET);
411                 return;
412         }
413
414         set_host_byte(cmd, DID_OK);
415         if (message != COMMAND_COMPLETE)
416                 scsi_msg_to_host_byte(cmd, message);
417         set_status_byte(cmd, status);
418         return;
419 }
420
421 /*
422  *      Interrupt handler
423  */
424
425 static void ql_ihandl(void *dev_id)
426 {
427         struct scsi_cmnd *icmd;
428         struct Scsi_Host *host = dev_id;
429         struct qlogicfas408_priv *priv = get_priv_by_host(host);
430         int qbase = priv->qbase;
431         REG0;
432
433         if (!(inb(qbase + 4) & 0x80))   /* false alarm? */
434                 return;
435
436         if (priv->qlcmd == NULL) {      /* no command to process? */
437                 int i;
438                 i = 16;
439                 while (i-- && inb(qbase + 5));  /* maybe also ql_zap() */
440                 return;
441         }
442         icmd = priv->qlcmd;
443         ql_pcmd(icmd);
444         priv->qlcmd = NULL;
445         /*
446          *      If result is CHECK CONDITION done calls qcommand to request
447          *      sense
448          */
449         scsi_done(icmd);
450 }
451
452 irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
453 {
454         unsigned long flags;
455         struct Scsi_Host *host = dev_id;
456
457         spin_lock_irqsave(host->host_lock, flags);
458         ql_ihandl(dev_id);
459         spin_unlock_irqrestore(host->host_lock, flags);
460         return IRQ_HANDLED;
461 }
462
463 /*
464  *      Queued command
465  */
466
467 static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd)
468 {
469         void (*done)(struct scsi_cmnd *) = scsi_done;
470         struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
471
472         set_host_byte(cmd, DID_OK);
473         set_status_byte(cmd, SAM_STAT_GOOD);
474         if (scmd_id(cmd) == priv->qinitid) {
475                 set_host_byte(cmd, DID_BAD_TARGET);
476                 done(cmd);
477                 return 0;
478         }
479
480         /* wait for the last command's interrupt to finish */
481         while (priv->qlcmd != NULL) {
482                 barrier();
483                 cpu_relax();
484         }
485         ql_icmd(cmd);
486         return 0;
487 }
488
489 DEF_SCSI_QCMD(qlogicfas408_queuecommand)
490
491 /*
492  *      Return bios parameters
493  */
494
495 int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
496                            sector_t capacity, int ip[])
497 {
498 /* This should mimic the DOS Qlogic driver's behavior exactly */
499         ip[0] = 0x40;
500         ip[1] = 0x20;
501         ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
502         if (ip[2] > 1024) {
503                 ip[0] = 0xff;
504                 ip[1] = 0x3f;
505                 ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
506 #if 0
507                 if (ip[2] > 1023)
508                         ip[2] = 1023;
509 #endif
510         }
511         return 0;
512 }
513
514 /*
515  *      Abort a command in progress
516  */
517
518 int qlogicfas408_abort(struct scsi_cmnd *cmd)
519 {
520         struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
521         priv->qabort = 1;
522         ql_zap(priv);
523         return SUCCESS;
524 }
525
526 /*
527  *      Reset SCSI bus
528  *      FIXME: This function is invoked with cmd = NULL directly by
529  *      the PCMCIA qlogic_stub code. This wants fixing
530  */
531
532 int qlogicfas408_host_reset(struct scsi_cmnd *cmd)
533 {
534         struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
535         unsigned long flags;
536
537         priv->qabort = 2;
538
539         spin_lock_irqsave(cmd->device->host->host_lock, flags);
540         ql_zap(priv);
541         spin_unlock_irqrestore(cmd->device->host->host_lock, flags);
542
543         return SUCCESS;
544 }
545
546 /*
547  *      Return info string
548  */
549
550 const char *qlogicfas408_info(struct Scsi_Host *host)
551 {
552         struct qlogicfas408_priv *priv = get_priv_by_host(host);
553         return priv->qinfo;
554 }
555
556 /*
557  *      Get type of chip
558  */
559
560 int qlogicfas408_get_chip_type(int qbase, int int_type)
561 {
562         REG1;
563         return inb(qbase + 0xe) & 0xf8;
564 }
565
566 /*
567  *      Perform initialization tasks
568  */
569
570 void qlogicfas408_setup(int qbase, int id, int int_type)
571 {
572         outb(1, qbase + 8);     /* set for PIO pseudo DMA */
573         REG0;
574         outb(0x40 | qlcfg8 | id, qbase + 8);    /* (ini) bus id, disable scsi rst */
575         outb(qlcfg5, qbase + 5);        /* select timer */
576         outb(qlcfg9, qbase + 9);        /* prescaler */
577
578 #if QL_RESET_AT_START
579         outb(3, qbase + 3);
580
581         REG1;
582         /* FIXME: timeout */
583         while (inb(qbase + 0xf) & 4)
584                 cpu_relax();
585
586         REG0;
587 #endif
588 }
589
590 /*
591  *      Checks if this is a QLogic FAS 408
592  */
593
594 int qlogicfas408_detect(int qbase, int int_type)
595 {
596         REG1;
597         return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
598                 ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
599 }
600
601 /*
602  *      Disable interrupts
603  */
604
605 void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv)
606 {
607         int qbase = priv->qbase;
608         int int_type = priv->int_type;
609
610         REG1;
611         outb(0, qbase + 0xb);   /* disable ints */
612 }
613
614 /*
615  *      Init and exit functions
616  */
617
618 static int __init qlogicfas408_init(void)
619 {
620         return 0;
621 }
622
623 static void __exit qlogicfas408_exit(void)
624 {
625
626 }
627
628 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
629 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
630 MODULE_LICENSE("GPL");
631 module_init(qlogicfas408_init);
632 module_exit(qlogicfas408_exit);
633
634 EXPORT_SYMBOL(qlogicfas408_info);
635 EXPORT_SYMBOL(qlogicfas408_queuecommand);
636 EXPORT_SYMBOL(qlogicfas408_abort);
637 EXPORT_SYMBOL(qlogicfas408_host_reset);
638 EXPORT_SYMBOL(qlogicfas408_biosparam);
639 EXPORT_SYMBOL(qlogicfas408_ihandl);
640 EXPORT_SYMBOL(qlogicfas408_get_chip_type);
641 EXPORT_SYMBOL(qlogicfas408_setup);
642 EXPORT_SYMBOL(qlogicfas408_detect);
643 EXPORT_SYMBOL(qlogicfas408_disable_ints);
644