drm/ast: Rename AST_IO_DAC_INDEX_WRITE to AST_IO_VGADWR
[linux-block.git] / drivers / scsi / qlogicfas408.c
CommitLineData
1da177e4
LT
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
5751a9ea 7 Copyright 1994, Tom Zerucha.
1da177e4 8 tz@execpc.com
5751a9ea 9
1da177e4
LT
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.
5751a9ea 25
fa195afe 26 Cleaned up 26/10/2002 by Alan Cox <alan@lxorguk.ukuu.org.uk> as part of the 2.5
1da177e4
LT
27 SCSI driver cleanup and audit. This driver still needs work on the
28 following
5751a9ea
HR
29 - Non terminating hardware waits
30 - Some layering violations with its pcmcia stub
1da177e4
LT
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
53555fb7
BVA
58#include <scsi/scsi.h>
59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_device.h>
61#include <scsi/scsi_eh.h>
1da177e4 62#include <scsi/scsi_host.h>
53555fb7 63#include <scsi/scsi_tcq.h>
1da177e4
LT
64#include "qlogicfas408.h"
65
66/*----------------------------------------------------------------*/
67static int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */
68static int qlcfg6 = SYNCXFRPD;
69static int qlcfg7 = SYNCOFFST;
70static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
71static int qlcfg9 = ((XTALFREQ + 4) / 5);
72static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
73
74/*----------------------------------------------------------------*/
75
76/*----------------------------------------------------------------*/
77/* local functions */
78/*----------------------------------------------------------------*/
79
80/* error recovery - reset everything */
81
82static 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 */
5751a9ea
HR
99
100static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request,
101 int reqlen)
1da177e4
LT
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 */
5751a9ea 116 if ((j = inb(qbase + 8)) & 4)
1da177e4
LT
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;
5751a9ea 131 while (reqlen && !((j & 0x10) && (j & 0xc0)))
1da177e4
LT
132 {
133 /* while bytes to receive and not empty */
134 j &= 0xc0;
5751a9ea 135 while (reqlen && !((j = inb(qbase + 8)) & 0x10))
1da177e4
LT
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)
d2e993ed 147 if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */
1da177e4
LT
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 */
5751a9ea 169 while (reqlen && !((j = inb(qbase + 8)) & 2))
1da177e4
LT
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/*
5751a9ea 183 * Wait for interrupt flag (polled - not real hardware interrupt)
1da177e4
LT
184 */
185
186static 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/*
5751a9ea 213 * Initiate scsi command - queueing handler
1da177e4
LT
214 * caller must hold host lock
215 */
216
a24342b9 217static void ql_icmd(struct scsi_cmnd *cmd)
1da177e4
LT
218{
219 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
5751a9ea 220 int qbase = priv->qbase;
1da177e4
LT
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);
d2e993ed 248 outb(qlcfg5, qbase + 5); /* select timer */
1da177e4
LT
249 outb(qlcfg9 & 7, qbase + 9); /* prescaler */
250/* outb(0x99, qbase + 5); */
422c0d61 251 outb(scmd_id(cmd), qbase + 4);
1da177e4
LT
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/*
5751a9ea 261 * Process scsi command - usually after interrupt
1da177e4
LT
262 */
263
9a588d23 264static void ql_pcmd(struct scsi_cmnd *cmd)
1da177e4
LT
265{
266 unsigned int i, j;
267 unsigned long k;
1da177e4
LT
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 */
1da177e4
LT
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) {
9a588d23
HR
281 set_host_byte(cmd, DID_NO_CONNECT);
282 return;
1da177e4
LT
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);
9a588d23
HR
288 set_host_byte(cmd, DID_BAD_INTR);
289 return;
1da177e4
LT
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);
9a588d23
HR
302 set_host_byte(cmd, DID_ERROR);
303 return;
1da177e4 304 }
9a588d23 305
1da177e4
LT
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 */
bc1ebfba 309 reqlen = scsi_bufflen(cmd);
1da177e4
LT
310 /* note that it won't work if transfers > 16M are requested */
311 if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */
bc1ebfba 312 struct scatterlist *sg;
1da177e4
LT
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;
bc1ebfba
FT
320
321 scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
322 if (priv->qabort) {
323 REG0;
9a588d23
HR
324 set_host_byte(cmd,
325 priv->qabort == 1 ?
326 DID_ABORT : DID_RESET);
1da177e4 327 }
45711f1a 328 buf = sg_virt(sg);
bc1ebfba
FT
329 if (ql_pdma(priv, phase, buf, sg->length))
330 break;
1da177e4
LT
331 }
332 REG0;
9a588d23 333 rtrc(2);
1da177e4
LT
334 /*
335 * Wait for irq (split into second state of irq handler
5751a9ea 336 * if this can take time)
1da177e4 337 */
9a588d23
HR
338 if ((k = ql_wai(priv))) {
339 set_host_byte(cmd, k);
340 return;
341 }
1da177e4
LT
342 k = inb(qbase + 5); /* should be 0x10, bus service */
343 }
344
345 /*
5751a9ea 346 * Enter Status (and Message In) Phase
1da177e4 347 */
5751a9ea 348
1da177e4
LT
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);
9a588d23
HR
357 set_host_byte(cmd, DID_TIME_OUT);
358 return;
1da177e4
LT
359 }
360
361 /* FIXME: timeout ?? */
362 while (inb(qbase + 5))
363 cpu_relax(); /* clear pending ints */
364
9a588d23
HR
365 if (priv->qabort) {
366 set_host_byte(cmd,
367 priv->qabort == 1 ? DID_ABORT : DID_RESET);
368 return;
369 }
1da177e4
LT
370
371 outb(0x11, qbase + 3); /* get status and message */
9a588d23
HR
372 if ((k = ql_wai(priv))) {
373 set_host_byte(cmd, k);
374 return;
375 }
1da177e4
LT
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 /*
5751a9ea
HR
382 * Should get function complete int if Status and message, else
383 * bus serv if only status
1da177e4
LT
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);
9a588d23 387 set_host_byte(cmd, DID_ERROR);
1da177e4
LT
388 }
389 outb(0x12, qbase + 3); /* done, disconnect */
9a588d23
HR
390 rtrc(1);
391 if ((k = ql_wai(priv))) {
392 set_host_byte(cmd, k);
393 return;
394 }
1da177e4
LT
395
396 /*
5751a9ea 397 * Should get bus service interrupt and disconnect interrupt
1da177e4 398 */
5751a9ea 399
1da177e4
LT
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 }
9a588d23 406 rtrc(0);
1da177e4 407
9a588d23
HR
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;
1da177e4
LT
419}
420
421/*
5751a9ea 422 * Interrupt handler
1da177e4
LT
423 */
424
c7bec5ab 425static void ql_ihandl(void *dev_id)
1da177e4 426{
a24342b9 427 struct scsi_cmnd *icmd;
c7bec5ab 428 struct Scsi_Host *host = dev_id;
1da177e4
LT
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;
9a588d23 443 ql_pcmd(icmd);
1da177e4
LT
444 priv->qlcmd = NULL;
445 /*
5751a9ea
HR
446 * If result is CHECK CONDITION done calls qcommand to request
447 * sense
1da177e4 448 */
da65bc05 449 scsi_done(icmd);
1da177e4
LT
450}
451
7d12e780 452irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
1da177e4
LT
453{
454 unsigned long flags;
455 struct Scsi_Host *host = dev_id;
456
457 spin_lock_irqsave(host->host_lock, flags);
c7bec5ab 458 ql_ihandl(dev_id);
1da177e4
LT
459 spin_unlock_irqrestore(host->host_lock, flags);
460 return IRQ_HANDLED;
461}
462
463/*
464 * Queued command
465 */
466
af049dfd 467static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd)
1da177e4 468{
af049dfd 469 void (*done)(struct scsi_cmnd *) = scsi_done;
1da177e4 470 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
9a588d23
HR
471
472 set_host_byte(cmd, DID_OK);
473 set_status_byte(cmd, SAM_STAT_GOOD);
422c0d61 474 if (scmd_id(cmd) == priv->qinitid) {
9a588d23 475 set_host_byte(cmd, DID_BAD_TARGET);
1da177e4
LT
476 done(cmd);
477 return 0;
478 }
479
1da177e4
LT
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
f281233d
JG
489DEF_SCSI_QCMD(qlogicfas408_queuecommand)
490
5751a9ea
HR
491/*
492 * Return bios parameters
1da177e4
LT
493 */
494
a24342b9
H
495int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
496 sector_t capacity, int ip[])
1da177e4
LT
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 */
5751a9ea 517
a24342b9 518int qlogicfas408_abort(struct scsi_cmnd *cmd)
1da177e4
LT
519{
520 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
521 priv->qabort = 1;
522 ql_zap(priv);
523 return SUCCESS;
524}
525
4a56c1c1 526/*
1da177e4
LT
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
4a56c1c1 532int qlogicfas408_host_reset(struct scsi_cmnd *cmd)
1da177e4
LT
533{
534 struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
68b3aa7c
JG
535 unsigned long flags;
536
1da177e4 537 priv->qabort = 2;
68b3aa7c
JG
538
539 spin_lock_irqsave(cmd->device->host->host_lock, flags);
1da177e4 540 ql_zap(priv);
68b3aa7c
JG
541 spin_unlock_irqrestore(cmd->device->host->host_lock, flags);
542
1da177e4
LT
543 return SUCCESS;
544}
545
1da177e4
LT
546/*
547 * Return info string
548 */
549
550const 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
560int 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
570void 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
594int qlogicfas408_detect(int qbase, int int_type)
595{
5751a9ea 596 REG1;
1da177e4 597 return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
5751a9ea 598 ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
1da177e4
LT
599}
600
601/*
602 * Disable interrupts
603 */
604
605void 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
618static int __init qlogicfas408_init(void)
619{
620 return 0;
621}
622
623static void __exit qlogicfas408_exit(void)
624{
625
626}
627
628MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
629MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
630MODULE_LICENSE("GPL");
631module_init(qlogicfas408_init);
632module_exit(qlogicfas408_exit);
633
634EXPORT_SYMBOL(qlogicfas408_info);
635EXPORT_SYMBOL(qlogicfas408_queuecommand);
636EXPORT_SYMBOL(qlogicfas408_abort);
4a56c1c1 637EXPORT_SYMBOL(qlogicfas408_host_reset);
1da177e4
LT
638EXPORT_SYMBOL(qlogicfas408_biosparam);
639EXPORT_SYMBOL(qlogicfas408_ihandl);
640EXPORT_SYMBOL(qlogicfas408_get_chip_type);
641EXPORT_SYMBOL(qlogicfas408_setup);
642EXPORT_SYMBOL(qlogicfas408_detect);
643EXPORT_SYMBOL(qlogicfas408_disable_ints);
644