xref: /openbmc/linux/drivers/scsi/qlogicfas408.c (revision c4f7ac64)
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, 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(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 
259 static 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 
400 static 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 
427 irqreturn_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 
442 static 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 
462 DEF_SCSI_QCMD(qlogicfas408_queuecommand)
463 
464 /*
465  *	Return bios parameters
466  */
467 
468 int 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 
491 int 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 
505 int qlogicfas408_host_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 
523 const 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 
533 int 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 
543 void 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 
567 int 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 
578 void 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 
591 static int __init qlogicfas408_init(void)
592 {
593 	return 0;
594 }
595 
596 static void __exit qlogicfas408_exit(void)
597 {
598 
599 }
600 
601 MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
602 MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
603 MODULE_LICENSE("GPL");
604 module_init(qlogicfas408_init);
605 module_exit(qlogicfas408_exit);
606 
607 EXPORT_SYMBOL(qlogicfas408_info);
608 EXPORT_SYMBOL(qlogicfas408_queuecommand);
609 EXPORT_SYMBOL(qlogicfas408_abort);
610 EXPORT_SYMBOL(qlogicfas408_host_reset);
611 EXPORT_SYMBOL(qlogicfas408_biosparam);
612 EXPORT_SYMBOL(qlogicfas408_ihandl);
613 EXPORT_SYMBOL(qlogicfas408_get_chip_type);
614 EXPORT_SYMBOL(qlogicfas408_setup);
615 EXPORT_SYMBOL(qlogicfas408_detect);
616 EXPORT_SYMBOL(qlogicfas408_disable_ints);
617 
618