xref: /openbmc/linux/drivers/scsi/sun3_scsi_vme.c (revision 9829e528)
1  /*
2  * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
3  *
4  * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
5  *
6  * VME support added by Sam Creasey
7  *
8  * Adapted from sun3_scsi.c -- see there for other headers
9  *
10  * TODO: modify this driver to support multiple Sun3 SCSI VME boards
11  *
12  */
13 
14 #define AUTOSENSE
15 
16 #include <linux/types.h>
17 #include <linux/stddef.h>
18 #include <linux/ctype.h>
19 #include <linux/delay.h>
20 
21 #include <linux/module.h>
22 #include <linux/signal.h>
23 #include <linux/ioport.h>
24 #include <linux/init.h>
25 #include <linux/blkdev.h>
26 
27 #include <asm/io.h>
28 
29 #include <asm/sun3ints.h>
30 #include <asm/dvma.h>
31 #include <asm/idprom.h>
32 #include <asm/machines.h>
33 
34 #define SUN3_SCSI_VME
35 
36 #undef SUN3_SCSI_DEBUG
37 
38 /* dma on! */
39 #define REAL_DMA
40 
41 #include "scsi.h"
42 #include "initio.h"
43 #include <scsi/scsi_host.h>
44 #include "sun3_scsi.h"
45 
46 extern int sun3_map_test(unsigned long, char *);
47 
48 #define USE_WRAPPER
49 /*#define RESET_BOOT */
50 #define DRIVER_SETUP
51 
52 /*
53  * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
54  */
55 #ifdef BUG
56 #undef RESET_BOOT
57 #undef DRIVER_SETUP
58 #endif
59 
60 /* #define SUPPORT_TAGS */
61 
62 //#define	ENABLE_IRQ()	enable_irq( SUN3_VEC_VMESCSI0 );
63 #define ENABLE_IRQ()
64 
65 
66 static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
67 static inline unsigned char sun3scsi_read(int reg);
68 static inline void sun3scsi_write(int reg, int value);
69 
70 static int setup_can_queue = -1;
71 module_param(setup_can_queue, int, 0);
72 static int setup_cmd_per_lun = -1;
73 module_param(setup_cmd_per_lun, int, 0);
74 static int setup_sg_tablesize = -1;
75 module_param(setup_sg_tablesize, int, 0);
76 #ifdef SUPPORT_TAGS
77 static int setup_use_tagged_queuing = -1;
78 module_param(setup_use_tagged_queuing, int, 0);
79 #endif
80 static int setup_hostid = -1;
81 module_param(setup_hostid, int, 0);
82 
83 static struct scsi_cmnd *sun3_dma_setup_done = NULL;
84 
85 #define	AFTER_RESET_DELAY	(HZ/2)
86 
87 /* ms to wait after hitting dma regs */
88 #define SUN3_DMA_DELAY 10
89 
90 /* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
91 #define SUN3_DVMA_BUFSIZE 0xe000
92 
93 /* minimum number of bytes to do dma on */
94 #define SUN3_DMA_MINSIZE 128
95 
96 static volatile unsigned char *sun3_scsi_regp;
97 static volatile struct sun3_dma_regs *dregs;
98 #ifdef OLDDMA
99 static unsigned char *dmabuf = NULL; /* dma memory buffer */
100 #endif
101 static unsigned char *sun3_dma_orig_addr = NULL;
102 static unsigned long sun3_dma_orig_count = 0;
103 static int sun3_dma_active = 0;
104 static unsigned long last_residual = 0;
105 
106 /*
107  * NCR 5380 register access functions
108  */
109 
110 static inline unsigned char sun3scsi_read(int reg)
111 {
112 	return( sun3_scsi_regp[reg] );
113 }
114 
115 static inline void sun3scsi_write(int reg, int value)
116 {
117 	sun3_scsi_regp[reg] = value;
118 }
119 
120 /*
121  * XXX: status debug
122  */
123 static struct Scsi_Host *default_instance;
124 
125 /*
126  * Function : int sun3scsi_detect(struct scsi_host_template * tpnt)
127  *
128  * Purpose : initializes mac NCR5380 driver based on the
129  *	command line / compile time port and irq definitions.
130  *
131  * Inputs : tpnt - template for this SCSI adapter.
132  *
133  * Returns : 1 if a host adapter was found, 0 if not.
134  *
135  */
136 
137 static int __init sun3scsi_detect(struct scsi_host_template * tpnt)
138 {
139 	unsigned long ioaddr, irq = 0;
140 	static int called = 0;
141 	struct Scsi_Host *instance;
142 	int i;
143 	unsigned long addrs[3] = { IOBASE_SUN3_VMESCSI,
144 				   IOBASE_SUN3_VMESCSI + 0x4000,
145 				   0 };
146 	unsigned long vecs[3] = { SUN3_VEC_VMESCSI0,
147 				  SUN3_VEC_VMESCSI1,
148 				  0 };
149 	/* check that this machine has an onboard 5380 */
150 	switch(idprom->id_machtype) {
151 	case SM_SUN3|SM_3_160:
152 	case SM_SUN3|SM_3_260:
153 		break;
154 
155 	default:
156 		return 0;
157 	}
158 
159 	if(called)
160 		return 0;
161 
162 	tpnt->proc_name = "Sun3 5380 VME SCSI";
163 
164 	/* setup variables */
165 	tpnt->can_queue =
166 		(setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
167 	tpnt->cmd_per_lun =
168 		(setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
169 	tpnt->sg_tablesize =
170 		(setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
171 
172 	if (setup_hostid >= 0)
173 		tpnt->this_id = setup_hostid;
174 	else {
175 		/* use 7 as default */
176 		tpnt->this_id = 7;
177 	}
178 
179 	ioaddr = 0;
180 	for(i = 0; addrs[i] != 0; i++) {
181 		unsigned char x;
182 
183 		ioaddr = (unsigned long)sun3_ioremap(addrs[i], PAGE_SIZE,
184 						     SUN3_PAGE_TYPE_VME16);
185 		irq = vecs[i];
186 		sun3_scsi_regp = (unsigned char *)ioaddr;
187 
188 		dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
189 
190 		if(sun3_map_test((unsigned long)dregs, &x)) {
191 			unsigned short oldcsr;
192 
193 			oldcsr = dregs->csr;
194 			dregs->csr = 0;
195 			udelay(SUN3_DMA_DELAY);
196 			if(dregs->csr == 0x1400)
197 				break;
198 
199 			dregs->csr = oldcsr;
200 		}
201 
202 		iounmap((void *)ioaddr);
203 		ioaddr = 0;
204 	}
205 
206 	if(!ioaddr)
207 		return 0;
208 
209 #ifdef SUPPORT_TAGS
210 	if (setup_use_tagged_queuing < 0)
211 		setup_use_tagged_queuing = USE_TAGGED_QUEUING;
212 #endif
213 
214 	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
215 	if(instance == NULL)
216 		return 0;
217 
218 	default_instance = instance;
219 
220         instance->io_port = (unsigned long) ioaddr;
221 	instance->irq = irq;
222 
223 	NCR5380_init(instance, 0);
224 
225 	instance->n_io_port = 32;
226 
227         ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
228 
229 	if (request_irq(instance->irq, scsi_sun3_intr,
230 			0, "Sun3SCSI-5380VME", instance)) {
231 #ifndef REAL_DMA
232 		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
233 		       instance->host_no, instance->irq);
234 		instance->irq = SCSI_IRQ_NONE;
235 #else
236 		printk("scsi%d: IRQ%d not free, bailing out\n",
237 		       instance->host_no, instance->irq);
238 		return 0;
239 #endif
240 	}
241 
242 	printk("scsi%d: Sun3 5380 VME at port %lX irq", instance->host_no, instance->io_port);
243 	if (instance->irq == SCSI_IRQ_NONE)
244 		printk ("s disabled");
245 	else
246 		printk (" %d", instance->irq);
247 	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
248 	       instance->can_queue, instance->cmd_per_lun,
249 	       SUN3SCSI_PUBLIC_RELEASE);
250 	printk("\nscsi%d:", instance->host_no);
251 	NCR5380_print_options(instance);
252 	printk("\n");
253 
254 	dregs->csr = 0;
255 	udelay(SUN3_DMA_DELAY);
256 	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
257 	udelay(SUN3_DMA_DELAY);
258 	dregs->fifo_count = 0;
259 	dregs->fifo_count_hi = 0;
260 	dregs->dma_addr_hi = 0;
261 	dregs->dma_addr_lo = 0;
262 	dregs->dma_count_hi = 0;
263 	dregs->dma_count_lo = 0;
264 
265 	dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
266 
267 	called = 1;
268 
269 #ifdef RESET_BOOT
270 	sun3_scsi_reset_boot(instance);
271 #endif
272 
273 	return 1;
274 }
275 
276 int sun3scsi_release (struct Scsi_Host *shpnt)
277 {
278 	if (shpnt->irq != SCSI_IRQ_NONE)
279 		free_irq(shpnt->irq, shpnt);
280 
281 	iounmap((void *)sun3_scsi_regp);
282 
283 	NCR5380_exit(shpnt);
284 	return 0;
285 }
286 
287 #ifdef RESET_BOOT
288 /*
289  * Our 'bus reset on boot' function
290  */
291 
292 static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
293 {
294 	unsigned long end;
295 
296 	NCR5380_local_declare();
297 	NCR5380_setup(instance);
298 
299 	/*
300 	 * Do a SCSI reset to clean up the bus during initialization. No
301 	 * messing with the queues, interrupts, or locks necessary here.
302 	 */
303 
304 	printk( "Sun3 SCSI: resetting the SCSI bus..." );
305 
306 	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
307 //       	sun3_disable_irq( IRQ_SUN3_SCSI );
308 
309 	/* get in phase */
310 	NCR5380_write( TARGET_COMMAND_REG,
311 		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
312 
313 	/* assert RST */
314 	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
315 
316 	/* The min. reset hold time is 25us, so 40us should be enough */
317 	udelay( 50 );
318 
319 	/* reset RST and interrupt */
320 	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
321 	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
322 
323 	for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
324 		barrier();
325 
326 	/* switch on SCSI IRQ again */
327 //       	sun3_enable_irq( IRQ_SUN3_SCSI );
328 
329 	printk( " done\n" );
330 }
331 #endif
332 
333 static const char * sun3scsi_info (struct Scsi_Host *spnt) {
334     return "";
335 }
336 
337 // safe bits for the CSR
338 #define CSR_GOOD 0x060f
339 
340 static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
341 {
342 	unsigned short csr = dregs->csr;
343 	int handled = 0;
344 
345 	dregs->csr &= ~CSR_DMA_ENABLE;
346 
347 
348 #ifdef SUN3_SCSI_DEBUG
349 	printk("scsi_intr csr %x\n", csr);
350 #endif
351 
352 	if(csr & ~CSR_GOOD) {
353 		if(csr & CSR_DMA_BUSERR) {
354 			printk("scsi%d: bus error in dma\n", default_instance->host_no);
355 #ifdef SUN3_SCSI_DEBUG
356 			printk("scsi: residual %x count %x addr %p dmaaddr %x\n",
357 			       dregs->fifo_count,
358 			       dregs->dma_count_lo | (dregs->dma_count_hi << 16),
359 			       sun3_dma_orig_addr,
360 			       dregs->dma_addr_lo | (dregs->dma_addr_hi << 16));
361 #endif
362 		}
363 
364 		if(csr & CSR_DMA_CONFLICT) {
365 			printk("scsi%d: dma conflict\n", default_instance->host_no);
366 		}
367 		handled = 1;
368 	}
369 
370 	if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
371 		NCR5380_intr(irq, dummy);
372 		handled = 1;
373 	}
374 
375 	return IRQ_RETVAL(handled);
376 }
377 
378 /*
379  * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
380  * reentering NCR5380_print_status seems to have ugly side effects
381  */
382 
383 /* this doesn't seem to get used at all -- sam */
384 #if 0
385 void sun3_sun3_debug (void)
386 {
387 	unsigned long flags;
388 	NCR5380_local_declare();
389 
390 	if (default_instance) {
391 			local_irq_save(flags);
392 			NCR5380_print_status(default_instance);
393 			local_irq_restore(flags);
394 	}
395 }
396 #endif
397 
398 
399 /* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
400 static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
401 {
402 	void *addr;
403 
404 	if(sun3_dma_orig_addr != NULL)
405 		dvma_unmap(sun3_dma_orig_addr);
406 
407 //	addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf);
408 	addr = (void *)dvma_map_vme((unsigned long) data, count);
409 
410 	sun3_dma_orig_addr = addr;
411 	sun3_dma_orig_count = count;
412 
413 #ifdef SUN3_SCSI_DEBUG
414 	printk("scsi: dma_setup addr %p count %x\n", addr, count);
415 #endif
416 
417 //	dregs->fifo_count = 0;
418 #if 0
419 	/* reset fifo */
420 	dregs->csr &= ~CSR_FIFO;
421 	dregs->csr |= CSR_FIFO;
422 #endif
423 	/* set direction */
424 	if(write_flag)
425 		dregs->csr |= CSR_SEND;
426 	else
427 		dregs->csr &= ~CSR_SEND;
428 
429 	/* reset fifo */
430 //	dregs->csr &= ~CSR_FIFO;
431 //	dregs->csr |= CSR_FIFO;
432 
433 	dregs->csr |= CSR_PACK_ENABLE;
434 
435 	dregs->dma_addr_hi = ((unsigned long)addr >> 16);
436 	dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
437 
438 	dregs->dma_count_hi = 0;
439 	dregs->dma_count_lo = 0;
440 	dregs->fifo_count_hi = 0;
441 	dregs->fifo_count = 0;
442 
443 #ifdef SUN3_SCSI_DEBUG
444 	printk("scsi: dma_setup done csr %x\n", dregs->csr);
445 #endif
446        	return count;
447 
448 }
449 
450 static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
451 {
452 	return last_residual;
453 }
454 
455 static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted,
456 						  struct scsi_cmnd *cmd,
457 						  int write_flag)
458 {
459 	if (cmd->request->cmd_type == REQ_TYPE_FS)
460  		return wanted;
461 	else
462 		return 0;
463 }
464 
465 static int sun3scsi_dma_start(unsigned long count, char *data)
466 {
467 
468 	unsigned short csr;
469 
470 	csr = dregs->csr;
471 #ifdef SUN3_SCSI_DEBUG
472 	printk("scsi: dma_start data %p count %x csr %x fifo %x\n", data, count, csr, dregs->fifo_count);
473 #endif
474 
475 	dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
476 	dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
477 
478 	dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
479 	dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
480 
481 //	if(!(csr & CSR_DMA_ENABLE))
482 //		dregs->csr |= CSR_DMA_ENABLE;
483 
484 	return 0;
485 }
486 
487 /* clean up after our dma is done */
488 static int sun3scsi_dma_finish(int write_flag)
489 {
490 	unsigned short fifo;
491 	int ret = 0;
492 
493 	sun3_dma_active = 0;
494 
495 	dregs->csr &= ~CSR_DMA_ENABLE;
496 
497 	fifo = dregs->fifo_count;
498 	if(write_flag) {
499 		if((fifo > 0) && (fifo < sun3_dma_orig_count))
500 			fifo++;
501 	}
502 
503 	last_residual = fifo;
504 #ifdef SUN3_SCSI_DEBUG
505 	printk("scsi: residual %x total %x\n", fifo, sun3_dma_orig_count);
506 #endif
507 	/* empty bytes from the fifo which didn't make it */
508 	if((!write_flag) && (dregs->csr & CSR_LEFT)) {
509 		unsigned char *vaddr;
510 
511 #ifdef SUN3_SCSI_DEBUG
512 		printk("scsi: got left over bytes\n");
513 #endif
514 
515 		vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
516 
517 		vaddr += (sun3_dma_orig_count - fifo);
518 		vaddr--;
519 
520 		switch(dregs->csr & CSR_LEFT) {
521 		case CSR_LEFT_3:
522 			*vaddr = (dregs->bpack_lo & 0xff00) >> 8;
523 			vaddr--;
524 
525 		case CSR_LEFT_2:
526 			*vaddr = (dregs->bpack_hi & 0x00ff);
527 			vaddr--;
528 
529 		case CSR_LEFT_1:
530 			*vaddr = (dregs->bpack_hi & 0xff00) >> 8;
531 			break;
532 		}
533 
534 
535 	}
536 
537 	dvma_unmap(sun3_dma_orig_addr);
538 	sun3_dma_orig_addr = NULL;
539 
540 	dregs->dma_addr_hi = 0;
541 	dregs->dma_addr_lo = 0;
542 	dregs->dma_count_hi = 0;
543 	dregs->dma_count_lo = 0;
544 
545 	dregs->fifo_count = 0;
546 	dregs->fifo_count_hi = 0;
547 
548 	dregs->csr &= ~CSR_SEND;
549 
550 //	dregs->csr |= CSR_DMA_ENABLE;
551 
552 #if 0
553 	/* reset fifo */
554 	dregs->csr &= ~CSR_FIFO;
555 	dregs->csr |= CSR_FIFO;
556 #endif
557 	sun3_dma_setup_done = NULL;
558 
559 	return ret;
560 
561 }
562 
563 #include "sun3_NCR5380.c"
564 
565 static struct scsi_host_template driver_template = {
566 	.name			= SUN3_SCSI_NAME,
567 	.detect			= sun3scsi_detect,
568 	.release		= sun3scsi_release,
569 	.info			= sun3scsi_info,
570 	.queuecommand		= sun3scsi_queue_command,
571 	.eh_abort_handler      	= sun3scsi_abort,
572 	.eh_bus_reset_handler  	= sun3scsi_bus_reset,
573 	.can_queue		= CAN_QUEUE,
574 	.this_id		= 7,
575 	.sg_tablesize		= SG_TABLESIZE,
576 	.cmd_per_lun		= CMD_PER_LUN,
577 	.use_clustering		= DISABLE_CLUSTERING
578 };
579 
580 
581 #include "scsi_module.c"
582 
583 MODULE_LICENSE("GPL");
584