xref: /openbmc/linux/drivers/scsi/qlogicfas408.c (revision a5d46d9a)
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 	(icmd->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 			      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 
486 DEF_SCSI_QCMD(qlogicfas408_queuecommand)
487 
488 /*
489  *	Return bios parameters
490  */
491 
492 int 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 
515 int 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 
529 int 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 
547 const 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 
557 int 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 
567 void 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 
591 int 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 
602 void 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 
615 static int __init qlogicfas408_init(void)
616 {
617 	return 0;
618 }
619 
620 static void __exit qlogicfas408_exit(void)
621 {
622 
623 }
624 
625 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
626 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
627 MODULE_LICENSE("GPL");
628 module_init(qlogicfas408_init);
629 module_exit(qlogicfas408_exit);
630 
631 EXPORT_SYMBOL(qlogicfas408_info);
632 EXPORT_SYMBOL(qlogicfas408_queuecommand);
633 EXPORT_SYMBOL(qlogicfas408_abort);
634 EXPORT_SYMBOL(qlogicfas408_host_reset);
635 EXPORT_SYMBOL(qlogicfas408_biosparam);
636 EXPORT_SYMBOL(qlogicfas408_ihandl);
637 EXPORT_SYMBOL(qlogicfas408_get_chip_type);
638 EXPORT_SYMBOL(qlogicfas408_setup);
639 EXPORT_SYMBOL(qlogicfas408_detect);
640 EXPORT_SYMBOL(qlogicfas408_disable_ints);
641 
642