1 /* $NetBSD: mac68k5380.c,v 1.43 2005/12/11 12:18:02 christos Exp $ */
4 * Copyright (c) 1995 Allen Briggs
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
32 * Derived from atari5380.c for the mac68k port of NetBSD.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: mac68k5380.c,v 1.43 2005/12/11 12:18:02 christos Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/device.h>
43 #include <sys/syslog.h>
46 #include <uvm/uvm_extern.h>
48 #include <dev/scsipi/scsi_all.h>
49 #include <dev/scsipi/scsipi_all.h>
50 #include <dev/scsipi/scsi_message.h>
51 #include <dev/scsipi/scsiconf.h>
54 * Include the driver definitions
56 #include "ncr5380reg.h"
58 #include <machine/cpu.h>
59 #include <machine/stdarg.h>
60 #include <machine/viareg.h>
62 #include <mac68k/dev/ncr5380var.h>
65 * Set the various driver options
67 #define NREQ 18 /* Size of issue queue */
68 #define AUTO_SENSE 1 /* Automatically issue a request-sense */
70 #define DRNAME ncrscsi /* used in various prints */
71 #undef DBG_SEL /* Show the selection process */
72 #undef DBG_REQ /* Show enqueued/ready requests */
73 #undef DBG_NOWRITE /* Do not allow writes to the targets */
74 #undef DBG_PIO /* Show the polled-I/O process */
75 #undef DBG_INF /* Show information transfer process */
76 #define DBG_NOSTATIC /* No static functions, all in DDB trace*/
77 #define DBG_PID 25 /* Keep track of driver */
82 # define DBG_SELPRINT(a,b) printf(a,b)
84 # define DBG_SELPRINT(a,b)
87 # define DBG_PIOPRINT(a,b,c) printf(a,b,c)
89 # define DBG_PIOPRINT(a,b,c)
92 # define DBG_INFPRINT(a,b,c) a(b,c)
94 # define DBG_INFPRINT(a,b,c)
97 /* static char *last_hit = NULL, *olast_hit = NULL; */
98 static const char *last_hit
[DBG_PID
];
101 for (i = 0; i < DBG_PID - 1; i++) \
102 last_hit[i] = last_hit[i + 1]; \
103 last_hit[DBG_PID - 1] = a; }
108 #undef REAL_DMA /* Use DMA if sensible */
109 #define scsi_ipending() (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET)
110 #define fair_to_keep_dma() 1
111 #define claimed_dma() 1
112 #define reconsider_dma()
113 #define USE_PDMA 1 /* Use special pdma-transfer function */
114 #define MIN_PHYS 0x2000 /* pdma space w/ /DSACK is only 0x2000 */
116 #define ENABLE_NCR5380(sc) cur_softc = sc;
119 * softc of currently active controller (well, we only have one for now).
122 static struct ncr_softc
*cur_softc
;
125 volatile u_char scsi_5380
[8*16]; /* 8 regs, 1 every 16th byte. */
128 extern vaddr_t SCSIBase
;
129 static volatile u_char
*ncr
= (volatile u_char
*) 0x10000;
130 static volatile u_char
*ncr_5380_with_drq
= (volatile u_char
*) 0x6000;
131 static volatile u_char
*ncr_5380_without_drq
= (volatile u_char
*) 0x12000;
133 #define SCSI_5380 ((volatile struct scsi_5380 *) ncr)
134 #define GET_5380_REG(rnum) SCSI_5380->scsi_5380[((rnum)<<4)]
135 #define SET_5380_REG(rnum,val) (SCSI_5380->scsi_5380[((rnum)<<4)] = (val))
137 static void ncr5380_irq_intr(void *);
138 static void ncr5380_drq_intr(void *);
139 static void do_ncr5380_drq_intr(void *);
141 static inline void scsi_clr_ipend(void);
142 static void scsi_mach_init(struct ncr_softc
*);
143 static int machine_match(struct device
*, struct cfdata
*, void *,
145 static inline int pdma_ready(void);
146 static int transfer_pdma(u_char
*, u_char
*, u_long
*);
153 tmp
= GET_5380_REG(NCR5380_IRCV
);
158 scsi_mach_init(struct ncr_softc
*sc
)
160 static int initted
= 0;
163 panic("scsi_mach_init called again.");
165 ncr
= (volatile u_char
*)
166 (SCSIBase
+ (u_long
) ncr
);
167 ncr_5380_with_drq
= (volatile u_char
*)
168 (SCSIBase
+ (u_int
) ncr_5380_with_drq
);
169 ncr_5380_without_drq
= (volatile u_char
*)
170 (SCSIBase
+ (u_int
) ncr_5380_without_drq
);
172 if (VIA2
== VIA2OFF
) {
173 scsi_enable
= Via1Base
+ VIA2
* 0x2000 + vIER
;
174 scsi_flag
= Via1Base
+ VIA2
* 0x2000 + vIFR
;
176 scsi_enable
= Via1Base
+ VIA2
* 0x2000 + rIER
;
177 scsi_flag
= Via1Base
+ VIA2
* 0x2000 + rIFR
;
180 via2_register_irq(VIA2_SCSIIRQ
, ncr5380_irq_intr
, sc
);
181 via2_register_irq(VIA2_SCSIDRQ
, ncr5380_drq_intr
, sc
);
185 machine_match(struct device
*parent
, struct cfdata
*cf
, void *aux
,
188 if (!mac68k_machine
.scsi80
)
194 int pdma_5380_dir
= 0;
196 u_char
*pending_5380_data
;
197 u_long pending_5380_count
;
199 #define NCR5380_PDMA_DEBUG 1 /* Maybe we try with this off eventually. */
201 #if NCR5380_PDMA_DEBUG
202 int pdma_5380_sends
= 0;
203 int pdma_5380_bytes
= 0;
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",
212 printf("datap = %p, remainder = %ld.\n",
213 pending_5380_data
, pending_5380_count
);
221 SC_REQ
*reqp
= connected
;
225 PID("pdma_cleanup0");
229 #if NCR5380_PDMA_DEBUG
231 pdma_5380_bytes
+=(reqp
->xdata_len
- pending_5380_count
);
237 reqp
->xdata_ptr
+= reqp
->xdata_len
- pending_5380_count
;
238 reqp
->xdata_len
= pending_5380_count
;
243 SET_5380_REG(NCR5380_MODE
, GET_5380_REG(NCR5380_MODE
) & ~SC_M_DMA
);
246 * Clear any pending interrupts.
251 * Tell interrupt functions that DMA has ended.
253 reqp
->dr_flag
&= ~DRIVER_IN_DMA
;
255 SET_5380_REG(NCR5380_MODE
, IMODE_BASE
);
256 SET_5380_REG(NCR5380_ICOM
, 0);
261 * Back for more punishment.
263 PID("pdma_cleanup1");
265 PID("pdma_cleanup2");
273 SC_REQ
*reqp
= connected
;
275 extern u_char ncr5380_no_parchk
;
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.
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
)) ) {
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
;
300 /* XXX: is this the right reaction? */
303 } else if ( !(idstat
& SC_S_REQ
)
304 || (((idstat
>>2) & 7) != reqp
->phase
)) {
306 /* XXX: is this the right reaction? Can this happen? */
308 printf("Unexpected phase change.\n");
310 reqp
->xs
->error
= XS_DRIVER_STUFFUP
;
315 panic("Spurious interrupt during PDMA xfer.");
324 ncr5380_irq_intr(void *p
)
334 ncr_ctrl_intr(cur_softc
);
338 * This is the meat of the PDMA transfer.
339 * When we get here, we shove data as fast as the mac can take it.
340 * We depend on several things:
341 * * All macs after the Mac Plus that have a 5380 chip should have a general
342 * logic IC that handshakes data for blind transfers.
343 * * If the SCSI controller finishes sending/receiving data before we do,
344 * the same general logic IC will generate a /BERR for us in short order.
345 * * The fault address for said /BERR minus the base address for the
346 * transfer will be the amount of data that was actually written.
348 * We use the nofault flag and the setjmp/longjmp in locore.s so we can
349 * detect and handle the bus error for early termination of a command.
350 * This is usually caused by a disconnecting target.
353 do_ncr5380_drq_intr(void *p
)
356 extern int *nofault
, m68k_fault_addr
;
359 volatile u_int32_t
*long_drq
;
360 u_int32_t
*long_data
;
361 volatile u_int8_t
*drq
, tmp_data
;
365 if (pdma_5380_dir
== 2) {
373 * Setup for a possible bus error caused by SCSI controller
374 * switching out of DATA-IN/OUT before we're done with the
377 nofault
= (int *) &faultbuf
;
379 if (setjmp((label_t
*) nofault
)) {
382 count
= ( (u_long
) m68k_fault_addr
383 - (u_long
) ncr_5380_with_drq
);
384 if ((count
< 0) || (count
> pending_5380_count
)) {
385 printf("pdma %s: cnt = %d (0x%x) (pending cnt %ld)\n",
386 (pdma_5380_dir
== 2) ? "in" : "out",
387 count
, count
, pending_5380_count
);
388 panic("something is wrong");
391 pending_5380_data
+= count
;
392 pending_5380_count
-= count
;
396 PID("end drq early");
401 if (pdma_5380_dir
== 2) { /* Data In */
405 * Get the dest address aligned.
407 resid
= count
= min(pending_5380_count
,
408 4 - (((int) pending_5380_data
) & 0x3));
409 if (count
&& (count
< 4)) {
410 data
= (u_int8_t
*) pending_5380_data
;
411 drq
= (volatile u_int8_t
*) ncr_5380_with_drq
;
413 #define R1 *data++ = *drq++
417 pending_5380_data
+= resid
;
418 pending_5380_count
-= resid
;
422 * Get ready to start the transfer.
424 while (pending_5380_count
) {
427 dcount
= count
= min(pending_5380_count
, MIN_PHYS
);
428 long_drq
= (volatile u_int32_t
*) ncr_5380_with_drq
;
429 long_data
= (u_int32_t
*) pending_5380_data
;
431 #define R4 *long_data++ = *long_drq++
432 while ( count
> 64 ) {
433 R4
; R4
; R4
; R4
; R4
; R4
; R4
; R4
;
434 R4
; R4
; R4
; R4
; R4
; R4
; R4
; R4
; /* 64 */
441 data
= (u_int8_t
*) long_data
;
442 drq
= (volatile u_int8_t
*) long_drq
;
444 #define R1 *data++ = *drq++
448 pending_5380_count
-= dcount
;
449 pending_5380_data
+= dcount
;
455 * Get the source address aligned.
457 resid
= count
= min(pending_5380_count
,
458 4 - (((int) pending_5380_data
) & 0x3));
459 if (count
&& (count
< 4)) {
460 data
= (u_int8_t
*) pending_5380_data
;
461 drq
= (volatile u_int8_t
*) ncr_5380_with_drq
;
463 #define W1 *drq++ = *data++
467 pending_5380_data
+= resid
;
468 pending_5380_count
-= resid
;
472 * Get ready to start the transfer.
474 while (pending_5380_count
) {
477 dcount
= count
= min(pending_5380_count
, MIN_PHYS
);
478 long_drq
= (volatile u_int32_t
*) ncr_5380_with_drq
;
479 long_data
= (u_int32_t
*) pending_5380_data
;
481 #define W4 *long_drq++ = *long_data++
482 while ( count
> 64 ) {
483 W4
; W4
; W4
; W4
; W4
; W4
; W4
; W4
;
484 W4
; W4
; W4
; W4
; W4
; W4
; W4
; W4
; /* 64 */
487 while ( count
> 8 ) {
492 data
= (u_int8_t
*) long_data
;
493 drq
= (volatile u_int8_t
*) long_drq
;
495 #define W1 *drq++ = *data++
499 pending_5380_count
-= dcount
;
500 pending_5380_data
+= dcount
;
503 PID("write complete");
505 drq
= (volatile u_int8_t
*) ncr_5380_with_drq
;
508 PID("read a byte to force a phase change");
512 * OK. No bus error occurred above. Clear the nofault flag
513 * so we no longer short-circuit bus errors.
521 #endif /* if USE_PDMA */
525 ncr5380_drq_intr(void *p
)
527 while (GET_5380_REG(NCR5380_DMSTAT
) & SC_DMA_REQ
) {
528 do_ncr5380_drq_intr(p
);
535 #define SCSI_TIMEOUT_VAL 10000000
538 transfer_pdma(u_char
*phasep
, u_char
*data
, u_long
*count
)
540 SC_REQ
*reqp
= connected
;
541 int len
= *count
, s
, scsi_timeout
= SCSI_TIMEOUT_VAL
;
544 panic("ncrscsi: transfer_pdma called when operation already "
547 PID("transfer_pdma0")
550 * Don't bother with PDMA if we can't sleep or for small transfers.
552 if (reqp
->dr_flag
& DRIVER_NOINT
) {
553 PID("pdma, falling back to transfer_pio.")
554 transfer_pio(phasep
, data
, count
, 0);
559 * We are probably already at spl2(), so this is likely a no-op.
567 * Match phases with target.
569 SET_5380_REG(NCR5380_TCOM
, *phasep
);
572 * Clear pending interrupts.
577 * Wait until target asserts BSY.
579 while ( ((GET_5380_REG(NCR5380_IDSTAT
) & SC_S_BSY
) == 0)
580 && (--scsi_timeout
) );
583 printf("scsi timeout: waiting for BSY in %s.\n",
584 (*phasep
== PH_DATAOUT
) ? "pdma_out" : "pdma_in");
586 goto scsi_timeout_error
;
590 * Tell the driver that we're in DMA mode.
592 reqp
->dr_flag
|= DRIVER_IN_DMA
;
595 * Load transfer values for DRQ interrupt handlers.
597 pending_5380_data
= data
;
598 pending_5380_count
= len
;
601 * Set the transfer function to be called on DRQ interrupts.
602 * And note that we're waiting.
606 panic("Unexpected phase in transfer_pdma.");
609 SET_5380_REG(NCR5380_ICOM
, GET_5380_REG(NCR5380_ICOM
)|SC_ADTB
);
610 SET_5380_REG(NCR5380_MODE
, GET_5380_REG(NCR5380_MODE
)|SC_M_DMA
);
611 SET_5380_REG(NCR5380_DMSTAT
, 0);
615 SET_5380_REG(NCR5380_ICOM
, 0);
616 SET_5380_REG(NCR5380_MODE
, GET_5380_REG(NCR5380_MODE
)|SC_M_DMA
);
617 SET_5380_REG(NCR5380_IRCV
, 0);
621 PID("waiting for interrupt.")
624 * Now that we're set up, enable interrupts and drop processor
625 * priority back down.
633 * Clear the DMA mode.
635 SET_5380_REG(NCR5380_MODE
, GET_5380_REG(NCR5380_MODE
) & ~SC_M_DMA
);
638 #endif /* if USE_PDMA */
640 /* Include general routines. */
641 #include <mac68k/dev/ncr5380.c>