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