xref: /openbmc/linux/drivers/scsi/qlogicfas408.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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  
ql_zap(struct qlogicfas408_priv * priv)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  
ql_pdma(struct qlogicfas408_priv * priv,int phase,char * request,int reqlen)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  
ql_wai(struct qlogicfas408_priv * priv)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  
ql_icmd(struct scsi_cmnd * cmd)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  
ql_pcmd(struct scsi_cmnd * cmd)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  
ql_ihandl(void * dev_id)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  
qlogicfas408_ihandl(int irq,void * dev_id)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  
qlogicfas408_queuecommand_lck(struct scsi_cmnd * cmd)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  
DEF_SCSI_QCMD(qlogicfas408_queuecommand)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  
qlogicfas408_abort(struct scsi_cmnd * cmd)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  
qlogicfas408_host_reset(struct scsi_cmnd * cmd)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  
qlogicfas408_info(struct Scsi_Host * host)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  
qlogicfas408_get_chip_type(int qbase,int int_type)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  
qlogicfas408_setup(int qbase,int id,int int_type)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  
qlogicfas408_detect(int qbase,int int_type)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  
qlogicfas408_disable_ints(struct qlogicfas408_priv * priv)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  
qlogicfas408_init(void)618  static int __init qlogicfas408_init(void)
619  {
620  	return 0;
621  }
622  
qlogicfas408_exit(void)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  
645