Linux Audio

Check our new training course

Yocto distribution development and maintenance

Need a Yocto distribution for your embedded project?
Loading...
v3.1
  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/*----------------------------------------------------------------*/
 63static int qlcfg5 = (XTALFREQ << 5);	/* 15625/512 */
 64static int qlcfg6 = SYNCXFRPD;
 65static int qlcfg7 = SYNCOFFST;
 66static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
 67static int qlcfg9 = ((XTALFREQ + 4) / 5);
 68static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
 69
 70/*----------------------------------------------------------------*/
 71
 72/*----------------------------------------------------------------*/
 73/* local functions */
 74/*----------------------------------------------------------------*/
 75
 76/* error recovery - reset everything */
 77
 78static 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 
 96static 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
181static 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
212static 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
259static 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
400static 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
427irqreturn_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
442static 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
462DEF_SCSI_QCMD(qlogicfas408_queuecommand)
463
464/* 
465 *	Return bios parameters 
466 */
467
468int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
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 
491int qlogicfas408_abort(struct scsi_cmnd *cmd)
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
505int qlogicfas408_bus_reset(struct scsi_cmnd *cmd)
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
523const 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
533int 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
543void 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
567int 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
578void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv)
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
591static int __init qlogicfas408_init(void)
592{
593	return 0;
594}
595
596static void __exit qlogicfas408_exit(void)
597{
598
599}
600
601MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
602MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
603MODULE_LICENSE("GPL");
604module_init(qlogicfas408_init);
605module_exit(qlogicfas408_exit);
606
607EXPORT_SYMBOL(qlogicfas408_info);
608EXPORT_SYMBOL(qlogicfas408_queuecommand);
609EXPORT_SYMBOL(qlogicfas408_abort);
610EXPORT_SYMBOL(qlogicfas408_bus_reset);
611EXPORT_SYMBOL(qlogicfas408_biosparam);
612EXPORT_SYMBOL(qlogicfas408_ihandl);
613EXPORT_SYMBOL(qlogicfas408_get_chip_type);
614EXPORT_SYMBOL(qlogicfas408_setup);
615EXPORT_SYMBOL(qlogicfas408_detect);
616EXPORT_SYMBOL(qlogicfas408_disable_ints);
617
v5.14.15
  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/*----------------------------------------------------------------*/
 63static int qlcfg5 = (XTALFREQ << 5);	/* 15625/512 */
 64static int qlcfg6 = SYNCXFRPD;
 65static int qlcfg7 = SYNCOFFST;
 66static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
 67static int qlcfg9 = ((XTALFREQ + 4) / 5);
 68static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
 69
 70/*----------------------------------------------------------------*/
 71
 72/*----------------------------------------------------------------*/
 73/* local functions */
 74/*----------------------------------------------------------------*/
 75
 76/* error recovery - reset everything */
 77
 78static 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
 96static 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
182static 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
213static 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
260static 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
421static 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
448irqreturn_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
463static 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
486DEF_SCSI_QCMD(qlogicfas408_queuecommand)
487
488/*
489 *	Return bios parameters
490 */
491
492int 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
515int 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
529int 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
547const 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
557int 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
567void 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
591int 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
602void 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
615static int __init qlogicfas408_init(void)
616{
617	return 0;
618}
619
620static void __exit qlogicfas408_exit(void)
621{
622
623}
624
625MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
626MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
627MODULE_LICENSE("GPL");
628module_init(qlogicfas408_init);
629module_exit(qlogicfas408_exit);
630
631EXPORT_SYMBOL(qlogicfas408_info);
632EXPORT_SYMBOL(qlogicfas408_queuecommand);
633EXPORT_SYMBOL(qlogicfas408_abort);
634EXPORT_SYMBOL(qlogicfas408_host_reset);
635EXPORT_SYMBOL(qlogicfas408_biosparam);
636EXPORT_SYMBOL(qlogicfas408_ihandl);
637EXPORT_SYMBOL(qlogicfas408_get_chip_type);
638EXPORT_SYMBOL(qlogicfas408_setup);
639EXPORT_SYMBOL(qlogicfas408_detect);
640EXPORT_SYMBOL(qlogicfas408_disable_ints);
641