xref: /linux/drivers/scsi/qlogicfas408.c (revision f3d9478b2ce468c3115b02ecae7e975990697f15)
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@redhat.com> 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(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(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 	struct scatterlist *sglist;	/* scatter-gather list pointer */
269 	unsigned int sgcount;	/* sg counter */
270 	char *buf;
271 	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
272 	int qbase = priv->qbase;
273 	int int_type = priv->int_type;
274 
275 	rtrc(1)
276 	j = inb(qbase + 6);
277 	i = inb(qbase + 5);
278 	if (i == 0x20) {
279 		return (DID_NO_CONNECT << 16);
280 	}
281 	i |= inb(qbase + 5);	/* the 0x10 bit can be set after the 0x08 */
282 	if (i != 0x18) {
283 		printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
284 		ql_zap(priv);
285 		return (DID_BAD_INTR << 16);
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 		return (DID_ERROR << 16);
299 	}
300 	result = DID_OK;
301 	if (inb(qbase + 7) & 0x1f)	/* if some bytes in fifo */
302 		outb(1, qbase + 3);	/* clear fifo */
303 	/* note that request_bufflen is the total xfer size when sg is used */
304 	reqlen = cmd->request_bufflen;
305 	/* note that it won't work if transfers > 16M are requested */
306 	if (reqlen && !((phase = inb(qbase + 4)) & 6)) {	/* data phase */
307 		rtrc(2)
308 		outb(reqlen, qbase);	/* low-mid xfer cnt */
309 		outb(reqlen >> 8, qbase + 1);	/* low-mid xfer cnt */
310 		outb(reqlen >> 16, qbase + 0xe);	/* high xfer cnt */
311 		outb(0x90, qbase + 3);	/* command do xfer */
312 		/* PIO pseudo DMA to buffer or sglist */
313 		REG1;
314 		if (!cmd->use_sg)
315 			ql_pdma(priv, phase, cmd->request_buffer,
316 				cmd->request_bufflen);
317 		else {
318 			sgcount = cmd->use_sg;
319 			sglist = cmd->request_buffer;
320 			while (sgcount--) {
321 				if (priv->qabort) {
322 					REG0;
323 					return ((priv->qabort == 1 ?
324 						DID_ABORT : DID_RESET) << 16);
325 				}
326 				buf = page_address(sglist->page) + sglist->offset;
327 				if (ql_pdma(priv, phase, buf, sglist->length))
328 					break;
329 				sglist++;
330 			}
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 			return (k << 16);
340 		k = inb(qbase + 5);	/* should be 0x10, bus service */
341 	}
342 
343 	/*
344 	 *	Enter Status (and Message In) Phase
345 	 */
346 
347 	k = jiffies + WATCHDOG;
348 
349 	while (time_before(jiffies, k) && !priv->qabort &&
350 						!(inb(qbase + 4) & 6))
351 		cpu_relax();	/* wait for status phase */
352 
353 	if (time_after_eq(jiffies, k)) {
354 		ql_zap(priv);
355 		return (DID_TIME_OUT << 16);
356 	}
357 
358 	/* FIXME: timeout ?? */
359 	while (inb(qbase + 5))
360 		cpu_relax();	/* clear pending ints */
361 
362 	if (priv->qabort)
363 		return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
364 
365 	outb(0x11, qbase + 3);	/* get status and message */
366 	if ((k = ql_wai(priv)))
367 		return (k << 16);
368 	i = inb(qbase + 5);	/* get chip irq stat */
369 	j = inb(qbase + 7) & 0x1f;	/* and bytes rec'd */
370 	status = inb(qbase + 2);
371 	message = inb(qbase + 2);
372 
373 	/*
374 	 *	Should get function complete int if Status and message, else
375 	 *	bus serv if only status
376 	 */
377 	if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
378 		printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
379 		result = DID_ERROR;
380 	}
381 	outb(0x12, qbase + 3);	/* done, disconnect */
382 	rtrc(1)
383 	if ((k = ql_wai(priv)))
384 		return (k << 16);
385 
386 	/*
387 	 *	Should get bus service interrupt and disconnect interrupt
388 	 */
389 
390 	i = inb(qbase + 5);	/* should be bus service */
391 	while (!priv->qabort && ((i & 0x20) != 0x20)) {
392 		barrier();
393 		cpu_relax();
394 		i |= inb(qbase + 5);
395 	}
396 	rtrc(0)
397 
398 	if (priv->qabort)
399 		return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
400 
401 	return (result << 16) | (message << 8) | (status & STATUS_MASK);
402 }
403 
404 /*
405  *	Interrupt handler
406  */
407 
408 static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
409 {
410 	Scsi_Cmnd *icmd;
411 	struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
412 	struct qlogicfas408_priv *priv = get_priv_by_host(host);
413 	int qbase = priv->qbase;
414 	REG0;
415 
416 	if (!(inb(qbase + 4) & 0x80))	/* false alarm? */
417 		return;
418 
419 	if (priv->qlcmd == NULL) {	/* no command to process? */
420 		int i;
421 		i = 16;
422 		while (i-- && inb(qbase + 5));	/* maybe also ql_zap() */
423 		return;
424 	}
425 	icmd = priv->qlcmd;
426 	icmd->result = ql_pcmd(icmd);
427 	priv->qlcmd = NULL;
428 	/*
429 	 *	If result is CHECK CONDITION done calls qcommand to request
430 	 *	sense
431 	 */
432 	(icmd->scsi_done) (icmd);
433 }
434 
435 irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs)
436 {
437 	unsigned long flags;
438 	struct Scsi_Host *host = dev_id;
439 
440 	spin_lock_irqsave(host->host_lock, flags);
441 	ql_ihandl(irq, dev_id, regs);
442 	spin_unlock_irqrestore(host->host_lock, flags);
443 	return IRQ_HANDLED;
444 }
445 
446 /*
447  *	Queued command
448  */
449 
450 int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
451 {
452 	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
453 	if (scmd_id(cmd) == priv->qinitid) {
454 		cmd->result = DID_BAD_TARGET << 16;
455 		done(cmd);
456 		return 0;
457 	}
458 
459 	cmd->scsi_done = done;
460 	/* wait for the last command's interrupt to finish */
461 	while (priv->qlcmd != NULL) {
462 		barrier();
463 		cpu_relax();
464 	}
465 	ql_icmd(cmd);
466 	return 0;
467 }
468 
469 /*
470  *	Return bios parameters
471  */
472 
473 int qlogicfas408_biosparam(struct scsi_device * disk,
474 		        struct block_device *dev,
475 			sector_t capacity, int ip[])
476 {
477 /* This should mimic the DOS Qlogic driver's behavior exactly */
478 	ip[0] = 0x40;
479 	ip[1] = 0x20;
480 	ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
481 	if (ip[2] > 1024) {
482 		ip[0] = 0xff;
483 		ip[1] = 0x3f;
484 		ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
485 #if 0
486 		if (ip[2] > 1023)
487 			ip[2] = 1023;
488 #endif
489 	}
490 	return 0;
491 }
492 
493 /*
494  *	Abort a command in progress
495  */
496 
497 int qlogicfas408_abort(Scsi_Cmnd * cmd)
498 {
499 	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
500 	priv->qabort = 1;
501 	ql_zap(priv);
502 	return SUCCESS;
503 }
504 
505 /*
506  *	Reset SCSI bus
507  *	FIXME: This function is invoked with cmd = NULL directly by
508  *	the PCMCIA qlogic_stub code. This wants fixing
509  */
510 
511 int qlogicfas408_bus_reset(Scsi_Cmnd * cmd)
512 {
513 	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
514 	unsigned long flags;
515 
516 	priv->qabort = 2;
517 
518 	spin_lock_irqsave(cmd->device->host->host_lock, flags);
519 	ql_zap(priv);
520 	spin_unlock_irqrestore(cmd->device->host->host_lock, flags);
521 
522 	return SUCCESS;
523 }
524 
525 /*
526  *	Return info string
527  */
528 
529 const char *qlogicfas408_info(struct Scsi_Host *host)
530 {
531 	struct qlogicfas408_priv *priv = get_priv_by_host(host);
532 	return priv->qinfo;
533 }
534 
535 /*
536  *	Get type of chip
537  */
538 
539 int qlogicfas408_get_chip_type(int qbase, int int_type)
540 {
541 	REG1;
542 	return inb(qbase + 0xe) & 0xf8;
543 }
544 
545 /*
546  *	Perform initialization tasks
547  */
548 
549 void qlogicfas408_setup(int qbase, int id, int int_type)
550 {
551 	outb(1, qbase + 8);	/* set for PIO pseudo DMA */
552 	REG0;
553 	outb(0x40 | qlcfg8 | id, qbase + 8);	/* (ini) bus id, disable scsi rst */
554 	outb(qlcfg5, qbase + 5);	/* select timer */
555 	outb(qlcfg9, qbase + 9);	/* prescaler */
556 
557 #if QL_RESET_AT_START
558 	outb(3, qbase + 3);
559 
560 	REG1;
561 	/* FIXME: timeout */
562 	while (inb(qbase + 0xf) & 4)
563 		cpu_relax();
564 
565 	REG0;
566 #endif
567 }
568 
569 /*
570  *	Checks if this is a QLogic FAS 408
571  */
572 
573 int qlogicfas408_detect(int qbase, int int_type)
574 {
575         REG1;
576 	return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
577 	       ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
578 }
579 
580 /*
581  *	Disable interrupts
582  */
583 
584 void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv)
585 {
586 	int qbase = priv->qbase;
587 	int int_type = priv->int_type;
588 
589 	REG1;
590 	outb(0, qbase + 0xb);	/* disable ints */
591 }
592 
593 /*
594  *	Init and exit functions
595  */
596 
597 static int __init qlogicfas408_init(void)
598 {
599 	return 0;
600 }
601 
602 static void __exit qlogicfas408_exit(void)
603 {
604 
605 }
606 
607 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
608 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
609 MODULE_LICENSE("GPL");
610 module_init(qlogicfas408_init);
611 module_exit(qlogicfas408_exit);
612 
613 EXPORT_SYMBOL(qlogicfas408_info);
614 EXPORT_SYMBOL(qlogicfas408_queuecommand);
615 EXPORT_SYMBOL(qlogicfas408_abort);
616 EXPORT_SYMBOL(qlogicfas408_bus_reset);
617 EXPORT_SYMBOL(qlogicfas408_biosparam);
618 EXPORT_SYMBOL(qlogicfas408_ihandl);
619 EXPORT_SYMBOL(qlogicfas408_get_chip_type);
620 EXPORT_SYMBOL(qlogicfas408_setup);
621 EXPORT_SYMBOL(qlogicfas408_detect);
622 EXPORT_SYMBOL(qlogicfas408_disable_ints);
623 
624