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