xref: /netbsd-src/sys/arch/mac68k/dev/mac68k5380.c (revision 1ffa7b76c40339c17a0fb2a09fac93f287cfc046)
1 /*	$NetBSD: mac68k5380.c,v 1.38 2003/04/02 01:09:19 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Allen Briggs
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Allen Briggs
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * Derived from atari5380.c for the mac68k port of NetBSD.
33  *
34  */
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/dkstat.h>
41 #include <sys/syslog.h>
42 #include <sys/buf.h>
43 
44 #include <uvm/uvm_extern.h>
45 
46 #include <dev/scsipi/scsi_all.h>
47 #include <dev/scsipi/scsipi_all.h>
48 #include <dev/scsipi/scsi_message.h>
49 #include <dev/scsipi/scsiconf.h>
50 
51 /*
52  * Include the driver definitions
53  */
54 #include "ncr5380reg.h"
55 
56 #include <machine/cpu.h>
57 #include <machine/stdarg.h>
58 #include <machine/viareg.h>
59 
60 #include <mac68k/dev/ncr5380var.h>
61 
62 /*
63  * Set the various driver options
64  */
65 #define	NREQ		18	/* Size of issue queue			*/
66 #define	AUTO_SENSE	1	/* Automatically issue a request-sense 	*/
67 
68 #define	DRNAME		ncrscsi	/* used in various prints	*/
69 #undef	DBG_SEL			/* Show the selection process		*/
70 #undef	DBG_REQ			/* Show enqueued/ready requests		*/
71 #undef	DBG_NOWRITE		/* Do not allow writes to the targets	*/
72 #undef	DBG_PIO			/* Show the polled-I/O process		*/
73 #undef	DBG_INF			/* Show information transfer process	*/
74 #define	DBG_NOSTATIC		/* No static functions, all in DDB trace*/
75 #define	DBG_PID		25	/* Keep track of driver			*/
76 #ifdef DBG_NOSTATIC
77 #	define	static
78 #endif
79 #ifdef DBG_SEL
80 #	define	DBG_SELPRINT(a,b)	printf(a,b)
81 #else
82 #	define DBG_SELPRINT(a,b)
83 #endif
84 #ifdef DBG_PIO
85 #	define DBG_PIOPRINT(a,b,c) 	printf(a,b,c)
86 #else
87 #	define DBG_PIOPRINT(a,b,c)
88 #endif
89 #ifdef DBG_INF
90 #	define DBG_INFPRINT(a,b,c)	a(b,c)
91 #else
92 #	define DBG_INFPRINT(a,b,c)
93 #endif
94 #ifdef DBG_PID
95 	/* static	char	*last_hit = NULL, *olast_hit = NULL; */
96 	static char *last_hit[DBG_PID];
97 #	define	PID(a)	\
98 	{ int i; \
99 	  for (i=0; i< DBG_PID-1; i++) \
100 		last_hit[i] = last_hit[i+1]; \
101 	  last_hit[DBG_PID-1] = a; }
102 #else
103 #	define	PID(a)
104 #endif
105 
106 #undef 	REAL_DMA		/* Use DMA if sensible			*/
107 #define scsi_ipending()		(GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET)
108 #define fair_to_keep_dma()	1
109 #define claimed_dma()		1
110 #define reconsider_dma()
111 #define	USE_PDMA	1	/* Use special pdma-transfer function	*/
112 #define MIN_PHYS	0x2000	/* pdma space w/ /DSACK is only 0x2000  */
113 
114 #define	ENABLE_NCR5380(sc)	cur_softc = sc;
115 
116 /*
117  * softc of currently active controller (well, we only have one for now).
118  */
119 
120 static struct ncr_softc	*cur_softc;
121 
122 struct scsi_5380 {
123 	volatile u_char	scsi_5380[8*16]; /* 8 regs, 1 every 16th byte. */
124 };
125 
126 extern vaddr_t		SCSIBase;
127 static volatile u_char	*ncr		= (volatile u_char *) 0x10000;
128 static volatile u_char	*ncr_5380_with_drq	= (volatile u_char *)  0x6000;
129 static volatile u_char	*ncr_5380_without_drq	= (volatile u_char *) 0x12000;
130 
131 #define SCSI_5380		((struct scsi_5380 *) ncr)
132 #define GET_5380_REG(rnum)	SCSI_5380->scsi_5380[((rnum)<<4)]
133 #define SET_5380_REG(rnum,val)	(SCSI_5380->scsi_5380[((rnum)<<4)] = (val))
134 
135 static void	ncr5380_irq_intr(void *);
136 static void	ncr5380_drq_intr(void *);
137 static void	do_ncr5380_drq_intr __P((void *));
138 
139 static __inline__ void	scsi_clr_ipend __P((void));
140 static		  void	scsi_mach_init __P((struct ncr_softc *sc));
141 static		  int	machine_match __P((struct device *parent,
142 			    struct cfdata *cf, void *aux,
143 			    struct cfdriver *cd));
144 static __inline__ int	pdma_ready __P((void));
145 static		  int	transfer_pdma __P((u_char *phasep, u_char *data,
146 					u_long *count));
147 
148 static __inline__ void
149 scsi_clr_ipend()
150 {
151 	int	tmp;
152 
153 	tmp = GET_5380_REG(NCR5380_IRCV);
154 	scsi_clear_irq();
155 }
156 
157 static void
158 scsi_mach_init(sc)
159 	struct ncr_softc	*sc;
160 {
161 	static int	initted = 0;
162 
163 	if (initted++)
164 		panic("scsi_mach_init called again.");
165 
166 	ncr		= (volatile u_char *)
167 			  (SCSIBase + (u_long) ncr);
168 	ncr_5380_with_drq	= (volatile u_char *)
169 			  (SCSIBase + (u_int) ncr_5380_with_drq);
170 	ncr_5380_without_drq	= (volatile u_char *)
171 			  (SCSIBase + (u_int) ncr_5380_without_drq);
172 
173 	if (VIA2 == VIA2OFF) {
174 		scsi_enable = Via1Base + VIA2 * 0x2000 + vIER;
175 		scsi_flag   = Via1Base + VIA2 * 0x2000 + vIFR;
176 	} else {
177 		scsi_enable = Via1Base + VIA2 * 0x2000 + rIER;
178 		scsi_flag   = Via1Base + VIA2 * 0x2000 + rIFR;
179 	}
180 
181 	via2_register_irq(VIA2_SCSIIRQ, ncr5380_irq_intr, sc);
182 	via2_register_irq(VIA2_SCSIDRQ, ncr5380_drq_intr, sc);
183 }
184 
185 static int
186 machine_match(parent, cf, aux, cd)
187 	struct device *parent;
188 	struct cfdata *cf;
189 	void *aux;
190 	struct cfdriver *cd;
191 {
192 	if (!mac68k_machine.scsi80)
193 		return 0;
194 	return 1;
195 }
196 
197 #if USE_PDMA
198 int	pdma_5380_dir = 0;
199 
200 u_char	*pending_5380_data;
201 u_long	pending_5380_count;
202 
203 #define NCR5380_PDMA_DEBUG 1 	/* Maybe we try with this off eventually. */
204 
205 #if NCR5380_PDMA_DEBUG
206 int		pdma_5380_sends = 0;
207 int		pdma_5380_bytes = 0;
208 
209 void
210 pdma_stat()
211 {
212 	printf("PDMA SCSI: %d xfers completed for %d bytes.\n",
213 		pdma_5380_sends, pdma_5380_bytes);
214 	printf("pdma_5380_dir = %d\t",
215 		pdma_5380_dir);
216 	printf("datap = %p, remainder = %ld.\n",
217 		pending_5380_data, pending_5380_count);
218 	scsi_show();
219 }
220 #endif
221 
222 void
223 pdma_cleanup(void)
224 {
225 	SC_REQ	*reqp = connected;
226 	int	s;
227 
228 	s = splbio();
229 	PID("pdma_cleanup0");
230 
231 	pdma_5380_dir = 0;
232 
233 #if NCR5380_PDMA_DEBUG
234 	pdma_5380_sends++;
235 	pdma_5380_bytes+=(reqp->xdata_len - pending_5380_count);
236 #endif
237 
238 	/*
239 	 * Update pointers.
240 	 */
241 	reqp->xdata_ptr += reqp->xdata_len - pending_5380_count;
242 	reqp->xdata_len  = pending_5380_count;
243 
244 	/*
245 	 * Reset DMA mode.
246 	 */
247 	SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
248 
249 	/*
250 	 * Clear any pending interrupts.
251 	 */
252 	scsi_clr_ipend();
253 
254 	/*
255 	 * Tell interrupt functions that DMA has ended.
256 	 */
257 	reqp->dr_flag &= ~DRIVER_IN_DMA;
258 
259 	SET_5380_REG(NCR5380_MODE, IMODE_BASE);
260 	SET_5380_REG(NCR5380_ICOM, 0);
261 
262 	splx(s);
263 
264 	/*
265 	 * Back for more punishment.
266 	 */
267 	PID("pdma_cleanup1");
268 	run_main(cur_softc);
269 	PID("pdma_cleanup2");
270 }
271 #endif
272 
273 static __inline__ int
274 pdma_ready()
275 {
276 #if USE_PDMA
277 	SC_REQ	*reqp = connected;
278 	int	dmstat, idstat;
279 extern	u_char	ncr5380_no_parchk;
280 
281 	PID("pdma_ready0");
282 	if (pdma_5380_dir) {
283 		PID("pdma_ready1.");
284 		/*
285 		 * For a phase mis-match, ATN is a "don't care," IRQ is 1 and
286 		 * all other bits in the Bus & Status Register are 0.  Also,
287 		 * the current SCSI Bus Status Register has a 1 for BSY and
288 		 * REQ.  Since we're just checking that this interrupt isn't a
289 		 * reselection or a reset, we just check for either.
290 		 */
291 		dmstat = GET_5380_REG(NCR5380_DMSTAT);
292 		idstat = GET_5380_REG(NCR5380_IDSTAT);
293 		if (   ((dmstat & (0xff & ~SC_ATN_STAT)) == SC_IRQ_SET)
294 		    && ((idstat & (SC_S_BSY|SC_S_REQ))
295 			== (SC_S_BSY | SC_S_REQ)) ) {
296 			PID("pdma_ready2");
297 			pdma_cleanup();
298 			return 1;
299 		} else if (PH_IN(reqp->phase) && (dmstat & SC_PAR_ERR)) {
300 			if (!(ncr5380_no_parchk & (1 << reqp->targ_id)))
301 				/* XXX: Should be parity error ???? */
302 				reqp->xs->error = XS_DRIVER_STUFFUP;
303 			PID("pdma_ready3");
304 			/* XXX: is this the right reaction? */
305 			pdma_cleanup();
306 			return 1;
307 		} else if (   !(idstat & SC_S_REQ)
308 			   || (((idstat>>2) & 7) != reqp->phase)) {
309 #ifdef DIAGNOSTIC
310 			/* XXX: is this the right reaction? Can this happen? */
311 			scsi_show();
312 			printf("Unexpected phase change.\n");
313 #endif
314 			reqp->xs->error = XS_DRIVER_STUFFUP;
315 			pdma_cleanup();
316 			return 1;
317 		} else {
318 			scsi_show();
319 			panic("Spurious interrupt during PDMA xfer.");
320 		}
321 	} else
322 		PID("pdma_ready4");
323 #endif
324 	return 0;
325 }
326 
327 static void
328 ncr5380_irq_intr(p)
329 	void	*p;
330 {
331 	PID("irq");
332 
333 #if USE_PDMA
334 	if (pdma_ready()) {
335 		return;
336 	}
337 #endif
338 	scsi_idisable();
339 	ncr_ctrl_intr(cur_softc);
340 }
341 
342 /*
343  * This is the meat of the PDMA transfer.
344  * When we get here, we shove data as fast as the mac can take it.
345  * We depend on several things:
346  *   * All macs after the Mac Plus that have a 5380 chip should have a general
347  *     logic IC that handshakes data for blind transfers.
348  *   * If the SCSI controller finishes sending/receiving data before we do,
349  *     the same general logic IC will generate a /BERR for us in short order.
350  *   * The fault address for said /BERR minus the base address for the
351  *     transfer will be the amount of data that was actually written.
352  *
353  * We use the nofault flag and the setjmp/longjmp in locore.s so we can
354  * detect and handle the bus error for early termination of a command.
355  * This is usually caused by a disconnecting target.
356  */
357 static void
358 do_ncr5380_drq_intr(p)
359 	void	*p;
360 {
361 #if USE_PDMA
362 extern	int			*nofault, m68k_fault_addr;
363 	label_t			faultbuf;
364 	register int		count;
365 	volatile u_int32_t	*long_drq;
366 	u_int32_t		*long_data;
367 	volatile u_int8_t	*drq, tmp_data;
368 	u_int8_t		*data;
369 
370 #if DBG_PID
371 	if (pdma_5380_dir == 2) {
372 		PID("drq (in)");
373 	} else {
374 		PID("drq (out)");
375 	}
376 #endif
377 
378 	/*
379 	 * Setup for a possible bus error caused by SCSI controller
380 	 * switching out of DATA-IN/OUT before we're done with the
381 	 * current transfer.
382 	 */
383 	nofault = (int *) &faultbuf;
384 
385 	if (setjmp((label_t *) nofault)) {
386 		PID("drq berr");
387 		nofault = (int *) 0;
388 		count = (  (u_long) m68k_fault_addr
389 			 - (u_long) ncr_5380_with_drq);
390 		if ((count < 0) || (count > pending_5380_count)) {
391 			printf("pdma %s: cnt = %d (0x%x) (pending cnt %ld)\n",
392 				(pdma_5380_dir == 2) ? "in" : "out",
393 				count, count, pending_5380_count);
394 			panic("something is wrong");
395 		}
396 
397 		pending_5380_data += count;
398 		pending_5380_count -= count;
399 
400 		m68k_fault_addr = 0;
401 
402 		PID("end drq early");
403 
404 		return;
405 	}
406 
407 	if (pdma_5380_dir == 2) { /* Data In */
408 		int	resid;
409 
410 		/*
411 		 * Get the dest address aligned.
412 		 */
413 		resid = count = min(pending_5380_count,
414 				    4 - (((int) pending_5380_data) & 0x3));
415 		if (count && (count < 4)) {
416 			data = (u_int8_t *) pending_5380_data;
417 			drq = (u_int8_t *) ncr_5380_with_drq;
418 			while (count) {
419 #define R1	*data++ = *drq++
420 				R1; count--;
421 #undef R1
422 			}
423 			pending_5380_data += resid;
424 			pending_5380_count -= resid;
425 		}
426 
427 		/*
428 		 * Get ready to start the transfer.
429 		 */
430 		while (pending_5380_count) {
431 		int dcount;
432 
433 		dcount = count = min(pending_5380_count, MIN_PHYS);
434 		long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
435 		long_data = (u_int32_t *) pending_5380_data;
436 
437 #define R4	*long_data++ = *long_drq++
438 		while ( count > 64 ) {
439 			R4; R4; R4; R4; R4; R4; R4; R4;
440 			R4; R4; R4; R4; R4; R4; R4; R4;	/* 64 */
441 			count -= 64;
442 		}
443 		while (count > 8) {
444 			R4; R4; count -= 8;
445 		}
446 #undef R4
447 		data = (u_int8_t *) long_data;
448 		drq = (u_int8_t *) long_drq;
449 		while (count) {
450 #define R1	*data++ = *drq++
451 			R1; count--;
452 #undef R1
453 		}
454 		pending_5380_count -= dcount;
455 		pending_5380_data += dcount;
456 		}
457 	} else {
458 		int	resid;
459 
460 		/*
461 		 * Get the source address aligned.
462 		 */
463 		resid = count = min(pending_5380_count,
464 				    4 - (((int) pending_5380_data) & 0x3));
465 		if (count && (count < 4)) {
466 			data = (u_int8_t *) pending_5380_data;
467 			drq = (u_int8_t *) ncr_5380_with_drq;
468 			while (count) {
469 #define W1	*drq++ = *data++
470 				W1; count--;
471 #undef W1
472 			}
473 			pending_5380_data += resid;
474 			pending_5380_count -= resid;
475 		}
476 
477 		/*
478 		 * Get ready to start the transfer.
479 		 */
480 		while (pending_5380_count) {
481 		int dcount;
482 
483 		dcount = count = min(pending_5380_count, MIN_PHYS);
484 		long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
485 		long_data = (u_int32_t *) pending_5380_data;
486 
487 #define W4	*long_drq++ = *long_data++
488 		while ( count > 64 ) {
489 			W4; W4; W4; W4; W4; W4; W4; W4;
490 			W4; W4; W4; W4; W4; W4; W4; W4; /*  64 */
491 			count -= 64;
492 		}
493 		while ( count > 8 ) {
494 			W4; W4;
495 			count -= 8;
496 		}
497 #undef W4
498 		data = (u_int8_t *) long_data;
499 		drq = (u_int8_t *) long_drq;
500 		while (count) {
501 #define W1	*drq++ = *data++
502 			W1; count--;
503 #undef W1
504 		}
505 		pending_5380_count -= dcount;
506 		pending_5380_data += dcount;
507 		}
508 
509 		PID("write complete");
510 
511 		drq = (volatile u_int8_t *) ncr_5380_with_drq;
512 		tmp_data = *drq;
513 
514 		PID("read a byte to force a phase change");
515 	}
516 
517 	/*
518 	 * OK.  No bus error occurred above.  Clear the nofault flag
519 	 * so we no longer short-circuit bus errors.
520 	 */
521 	nofault = (int *) 0;
522 
523 	PID("end drq");
524 	return;
525 #else
526 	return;
527 #endif	/* if USE_PDMA */
528 }
529 
530 static void
531 ncr5380_drq_intr(p)
532 	void	*p;
533 {
534 	while (GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ) {
535 		do_ncr5380_drq_intr(p);
536 		scsi_clear_drq();
537 	}
538 }
539 
540 #if USE_PDMA
541 
542 #define SCSI_TIMEOUT_VAL	10000000
543 
544 static int
545 transfer_pdma(phasep, data, count)
546 	u_char	*phasep;
547 	u_char	*data;
548 	u_long	*count;
549 {
550 	SC_REQ	*reqp = connected;
551 	int	len = *count, s, scsi_timeout = SCSI_TIMEOUT_VAL;
552 
553 	if (pdma_5380_dir) {
554 		panic("ncrscsi: transfer_pdma called when operation already "
555 			"pending.");
556 	}
557 	PID("transfer_pdma0")
558 
559 	/*
560  	 * Don't bother with PDMA if we can't sleep or for small transfers.
561  	 */
562 	if (reqp->dr_flag & DRIVER_NOINT) {
563 		PID("pdma, falling back to transfer_pio.")
564 		transfer_pio(phasep, data, count, 0);
565 		return -1;
566 	}
567 
568 	/*
569 	 * We are probably already at spl2(), so this is likely a no-op.
570 	 * Paranoia.
571 	 */
572 	s = splbio();
573 
574 	scsi_idisable();
575 
576 	/*
577 	 * Match phases with target.
578 	 */
579 	SET_5380_REG(NCR5380_TCOM, *phasep);
580 
581 	/*
582 	 * Clear pending interrupts.
583 	 */
584 	scsi_clr_ipend();
585 
586 	/*
587 	 * Wait until target asserts BSY.
588 	 */
589 	while (    ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0)
590 		&& (--scsi_timeout) );
591 	if (!scsi_timeout) {
592 #if DIAGNOSTIC
593 		printf("scsi timeout: waiting for BSY in %s.\n",
594 			(*phasep == PH_DATAOUT) ? "pdma_out" : "pdma_in");
595 #endif
596 		goto scsi_timeout_error;
597 	}
598 
599 	/*
600 	 * Tell the driver that we're in DMA mode.
601 	 */
602 	reqp->dr_flag |= DRIVER_IN_DMA;
603 
604 	/*
605 	 * Load transfer values for DRQ interrupt handlers.
606 	 */
607 	pending_5380_data = data;
608 	pending_5380_count = len;
609 
610 	/*
611 	 * Set the transfer function to be called on DRQ interrupts.
612 	 * And note that we're waiting.
613 	 */
614 	switch (*phasep) {
615 	default:
616 		panic("Unexpected phase in transfer_pdma.");
617 	case PH_DATAOUT:
618 		pdma_5380_dir = 1;
619 		SET_5380_REG(NCR5380_ICOM, GET_5380_REG(NCR5380_ICOM)|SC_ADTB);
620 		SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
621 		SET_5380_REG(NCR5380_DMSTAT, 0);
622 		break;
623 	case PH_DATAIN:
624 		pdma_5380_dir = 2;
625 		SET_5380_REG(NCR5380_ICOM, 0);
626 		SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
627 		SET_5380_REG(NCR5380_IRCV, 0);
628 		break;
629 	}
630 
631 	PID("waiting for interrupt.")
632 
633 	/*
634 	 * Now that we're set up, enable interrupts and drop processor
635 	 * priority back down.
636 	 */
637 	scsi_ienable();
638 	splx(s);
639 	return 0;
640 
641 scsi_timeout_error:
642 	/*
643 	 * Clear the DMA mode.
644 	 */
645 	SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
646 	return -1;
647 }
648 #endif /* if USE_PDMA */
649 
650 /* Include general routines. */
651 #include <mac68k/dev/ncr5380.c>
652