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