xref: /openbmc/linux/drivers/scsi/qlogicfas408.c (revision dfc66bef)
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 /*----------------------------------------------------------------*/
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,
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 
182 static 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 
213 static 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 
260 static 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 
421 static 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 	scsi_done(icmd);
446 }
447 
448 irqreturn_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 
463 static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd)
464 {
465 	void (*done)(struct scsi_cmnd *) = scsi_done;
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 	/* wait for the last command's interrupt to finish */
477 	while (priv->qlcmd != NULL) {
478 		barrier();
479 		cpu_relax();
480 	}
481 	ql_icmd(cmd);
482 	return 0;
483 }
484 
485 DEF_SCSI_QCMD(qlogicfas408_queuecommand)
486 
487 /*
488  *	Return bios parameters
489  */
490 
491 int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev,
492 			   sector_t capacity, int ip[])
493 {
494 /* This should mimic the DOS Qlogic driver's behavior exactly */
495 	ip[0] = 0x40;
496 	ip[1] = 0x20;
497 	ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
498 	if (ip[2] > 1024) {
499 		ip[0] = 0xff;
500 		ip[1] = 0x3f;
501 		ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
502 #if 0
503 		if (ip[2] > 1023)
504 			ip[2] = 1023;
505 #endif
506 	}
507 	return 0;
508 }
509 
510 /*
511  *	Abort a command in progress
512  */
513 
514 int qlogicfas408_abort(struct scsi_cmnd *cmd)
515 {
516 	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
517 	priv->qabort = 1;
518 	ql_zap(priv);
519 	return SUCCESS;
520 }
521 
522 /*
523  *	Reset SCSI bus
524  *	FIXME: This function is invoked with cmd = NULL directly by
525  *	the PCMCIA qlogic_stub code. This wants fixing
526  */
527 
528 int qlogicfas408_host_reset(struct scsi_cmnd *cmd)
529 {
530 	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
531 	unsigned long flags;
532 
533 	priv->qabort = 2;
534 
535 	spin_lock_irqsave(cmd->device->host->host_lock, flags);
536 	ql_zap(priv);
537 	spin_unlock_irqrestore(cmd->device->host->host_lock, flags);
538 
539 	return SUCCESS;
540 }
541 
542 /*
543  *	Return info string
544  */
545 
546 const char *qlogicfas408_info(struct Scsi_Host *host)
547 {
548 	struct qlogicfas408_priv *priv = get_priv_by_host(host);
549 	return priv->qinfo;
550 }
551 
552 /*
553  *	Get type of chip
554  */
555 
556 int qlogicfas408_get_chip_type(int qbase, int int_type)
557 {
558 	REG1;
559 	return inb(qbase + 0xe) & 0xf8;
560 }
561 
562 /*
563  *	Perform initialization tasks
564  */
565 
566 void qlogicfas408_setup(int qbase, int id, int int_type)
567 {
568 	outb(1, qbase + 8);	/* set for PIO pseudo DMA */
569 	REG0;
570 	outb(0x40 | qlcfg8 | id, qbase + 8);	/* (ini) bus id, disable scsi rst */
571 	outb(qlcfg5, qbase + 5);	/* select timer */
572 	outb(qlcfg9, qbase + 9);	/* prescaler */
573 
574 #if QL_RESET_AT_START
575 	outb(3, qbase + 3);
576 
577 	REG1;
578 	/* FIXME: timeout */
579 	while (inb(qbase + 0xf) & 4)
580 		cpu_relax();
581 
582 	REG0;
583 #endif
584 }
585 
586 /*
587  *	Checks if this is a QLogic FAS 408
588  */
589 
590 int qlogicfas408_detect(int qbase, int int_type)
591 {
592 	REG1;
593 	return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
594 		((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));
595 }
596 
597 /*
598  *	Disable interrupts
599  */
600 
601 void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv)
602 {
603 	int qbase = priv->qbase;
604 	int int_type = priv->int_type;
605 
606 	REG1;
607 	outb(0, qbase + 0xb);	/* disable ints */
608 }
609 
610 /*
611  *	Init and exit functions
612  */
613 
614 static int __init qlogicfas408_init(void)
615 {
616 	return 0;
617 }
618 
619 static void __exit qlogicfas408_exit(void)
620 {
621 
622 }
623 
624 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
625 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
626 MODULE_LICENSE("GPL");
627 module_init(qlogicfas408_init);
628 module_exit(qlogicfas408_exit);
629 
630 EXPORT_SYMBOL(qlogicfas408_info);
631 EXPORT_SYMBOL(qlogicfas408_queuecommand);
632 EXPORT_SYMBOL(qlogicfas408_abort);
633 EXPORT_SYMBOL(qlogicfas408_host_reset);
634 EXPORT_SYMBOL(qlogicfas408_biosparam);
635 EXPORT_SYMBOL(qlogicfas408_ihandl);
636 EXPORT_SYMBOL(qlogicfas408_get_chip_type);
637 EXPORT_SYMBOL(qlogicfas408_setup);
638 EXPORT_SYMBOL(qlogicfas408_detect);
639 EXPORT_SYMBOL(qlogicfas408_disable_ints);
640 
641