1*d1579b2dSriastradh /* $NetBSD: mac68k5380.c,v 1.50 2018/09/03 16:29:25 riastradh Exp $ */
2e46e8e7aSbriggs
3e46e8e7aSbriggs /*
4e46e8e7aSbriggs * Copyright (c) 1995 Allen Briggs
5e46e8e7aSbriggs * All rights reserved.
6e46e8e7aSbriggs *
7e46e8e7aSbriggs * Redistribution and use in source and binary forms, with or without
8e46e8e7aSbriggs * modification, are permitted provided that the following conditions
9e46e8e7aSbriggs * are met:
10e46e8e7aSbriggs * 1. Redistributions of source code must retain the above copyright
11e46e8e7aSbriggs * notice, this list of conditions and the following disclaimer.
12e46e8e7aSbriggs * 2. Redistributions in binary form must reproduce the above copyright
13e46e8e7aSbriggs * notice, this list of conditions and the following disclaimer in the
14e46e8e7aSbriggs * documentation and/or other materials provided with the distribution.
15e46e8e7aSbriggs * 3. All advertising materials mentioning features or use of this software
16e46e8e7aSbriggs * must display the following acknowledgement:
17e46e8e7aSbriggs * This product includes software developed by Allen Briggs
18e46e8e7aSbriggs * 4. The name of the author may not be used to endorse or promote products
19e46e8e7aSbriggs * derived from this software without specific prior written permission
20e46e8e7aSbriggs *
21e46e8e7aSbriggs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22e46e8e7aSbriggs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23e46e8e7aSbriggs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24e46e8e7aSbriggs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25e46e8e7aSbriggs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26e46e8e7aSbriggs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27e46e8e7aSbriggs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28e46e8e7aSbriggs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29e46e8e7aSbriggs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30e46e8e7aSbriggs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31e46e8e7aSbriggs *
32e46e8e7aSbriggs * Derived from atari5380.c for the mac68k port of NetBSD.
33e46e8e7aSbriggs *
34e46e8e7aSbriggs */
35e46e8e7aSbriggs
364b2744bfSlukem #include <sys/cdefs.h>
37*d1579b2dSriastradh __KERNEL_RCSID(0, "$NetBSD: mac68k5380.c,v 1.50 2018/09/03 16:29:25 riastradh Exp $");
384b2744bfSlukem
39e46e8e7aSbriggs #include <sys/param.h>
40e46e8e7aSbriggs #include <sys/systm.h>
41e46e8e7aSbriggs #include <sys/kernel.h>
42e46e8e7aSbriggs #include <sys/device.h>
43e46e8e7aSbriggs #include <sys/syslog.h>
44e46e8e7aSbriggs #include <sys/buf.h>
45d57736a7Sthorpej
46d57736a7Sthorpej #include <uvm/uvm_extern.h>
47d57736a7Sthorpej
486f3bab1fSbouyer #include <dev/scsipi/scsi_all.h>
496f3bab1fSbouyer #include <dev/scsipi/scsipi_all.h>
506f3bab1fSbouyer #include <dev/scsipi/scsi_message.h>
516f3bab1fSbouyer #include <dev/scsipi/scsiconf.h>
52e46e8e7aSbriggs
53e46e8e7aSbriggs /*
54e46e8e7aSbriggs * Include the driver definitions
55e46e8e7aSbriggs */
5637163421Sbriggs #include "ncr5380reg.h"
57e46e8e7aSbriggs
588a007407Sscottr #include <machine/cpu.h>
5908126b5bSbriggs #include <machine/viareg.h>
60e46e8e7aSbriggs
61c988c6f8Sscottr #include <mac68k/dev/ncr5380var.h>
6237163421Sbriggs
63e46e8e7aSbriggs /*
64e46e8e7aSbriggs * Set the various driver options
65e46e8e7aSbriggs */
66e46e8e7aSbriggs #define NREQ 18 /* Size of issue queue */
67e46e8e7aSbriggs #define AUTO_SENSE 1 /* Automatically issue a request-sense */
68e46e8e7aSbriggs
69e46e8e7aSbriggs #define DRNAME ncrscsi /* used in various prints */
70e46e8e7aSbriggs #undef DBG_SEL /* Show the selection process */
71e46e8e7aSbriggs #undef DBG_REQ /* Show enqueued/ready requests */
72e46e8e7aSbriggs #undef DBG_NOWRITE /* Do not allow writes to the targets */
73e46e8e7aSbriggs #undef DBG_PIO /* Show the polled-I/O process */
74e46e8e7aSbriggs #undef DBG_INF /* Show information transfer process */
75e46e8e7aSbriggs #define DBG_NOSTATIC /* No static functions, all in DDB trace*/
762a878c9aSbriggs #define DBG_PID 25 /* Keep track of driver */
772a878c9aSbriggs #ifdef DBG_NOSTATIC
782a878c9aSbriggs # define static
792a878c9aSbriggs #endif
802a878c9aSbriggs #ifdef DBG_SEL
8140ecbf8eSchristos # define DBG_SELPRINT(a,b) printf(a,b)
822a878c9aSbriggs #else
832a878c9aSbriggs # define DBG_SELPRINT(a,b)
842a878c9aSbriggs #endif
852a878c9aSbriggs #ifdef DBG_PIO
8640ecbf8eSchristos # define DBG_PIOPRINT(a,b,c) printf(a,b,c)
872a878c9aSbriggs #else
882a878c9aSbriggs # define DBG_PIOPRINT(a,b,c)
892a878c9aSbriggs #endif
902a878c9aSbriggs #ifdef DBG_INF
912a878c9aSbriggs # define DBG_INFPRINT(a,b,c) a(b,c)
922a878c9aSbriggs #else
932a878c9aSbriggs # define DBG_INFPRINT(a,b,c)
942a878c9aSbriggs #endif
952a878c9aSbriggs #ifdef DBG_PID
962a878c9aSbriggs /* static char *last_hit = NULL, *olast_hit = NULL; */
9761f16670Sjmc static const char *last_hit[DBG_PID];
982a878c9aSbriggs # define PID(a) \
992a878c9aSbriggs { int i; \
1002a878c9aSbriggs for (i = 0; i < DBG_PID - 1; i++) \
1012a878c9aSbriggs last_hit[i] = last_hit[i + 1]; \
1022a878c9aSbriggs last_hit[DBG_PID - 1] = a; }
1032a878c9aSbriggs #else
1042a878c9aSbriggs # define PID(a)
1052a878c9aSbriggs #endif
1062a878c9aSbriggs
107e46e8e7aSbriggs #undef REAL_DMA /* Use DMA if sensible */
108ab3f7419Sbriggs #define scsi_ipending() (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET)
109e46e8e7aSbriggs #define fair_to_keep_dma() 1
110e46e8e7aSbriggs #define claimed_dma() 1
111e46e8e7aSbriggs #define reconsider_dma()
112e46e8e7aSbriggs #define USE_PDMA 1 /* Use special pdma-transfer function */
113e23598f2Sbriggs #define MIN_PHYS 0x2000 /* pdma space w/ /DSACK is only 0x2000 */
114e46e8e7aSbriggs
115e46e8e7aSbriggs #define ENABLE_NCR5380(sc) cur_softc = sc;
116e46e8e7aSbriggs
117e46e8e7aSbriggs /*
118e46e8e7aSbriggs * softc of currently active controller (well, we only have one for now).
119e46e8e7aSbriggs */
120e46e8e7aSbriggs
121e46e8e7aSbriggs static struct ncr_softc *cur_softc;
122e46e8e7aSbriggs
123e46e8e7aSbriggs struct scsi_5380 {
124e46e8e7aSbriggs volatile u_char scsi_5380[8*16]; /* 8 regs, 1 every 16th byte. */
125e46e8e7aSbriggs };
126e46e8e7aSbriggs
12784af6365Sscottr extern vaddr_t SCSIBase;
128e46e8e7aSbriggs static volatile u_char *ncr = (volatile u_char *) 0x10000;
129e46e8e7aSbriggs static volatile u_char *ncr_5380_with_drq = (volatile u_char *) 0x6000;
130e46e8e7aSbriggs static volatile u_char *ncr_5380_without_drq = (volatile u_char *) 0x12000;
131e46e8e7aSbriggs
13261f16670Sjmc #define SCSI_5380 ((volatile struct scsi_5380 *) ncr)
133e46e8e7aSbriggs #define GET_5380_REG(rnum) SCSI_5380->scsi_5380[((rnum)<<4)]
134e46e8e7aSbriggs #define SET_5380_REG(rnum,val) (SCSI_5380->scsi_5380[((rnum)<<4)] = (val))
135e46e8e7aSbriggs
136014b4041Sbriggs static void ncr5380_irq_intr(void *);
137014b4041Sbriggs static void ncr5380_drq_intr(void *);
1387acd68b1Schs static void do_ncr5380_drq_intr(void *);
139a7783604Sbriggs
140a783fa47Smrg static void scsi_clr_ipend(void);
1417acd68b1Schs static void scsi_mach_init(struct ncr_softc *);
142cbab9cadSchs static int machine_match(device_t, cfdata_t, void *,
1437acd68b1Schs struct cfdriver *);
144a783fa47Smrg static int pdma_ready(void);
1457acd68b1Schs static int transfer_pdma(u_char *, u_char *, u_long *);
14637163421Sbriggs
147a783fa47Smrg static void
scsi_clr_ipend(void)1487acd68b1Schs scsi_clr_ipend(void)
149e46e8e7aSbriggs {
150e46e8e7aSbriggs
151652316b5Smartin GET_5380_REG(NCR5380_IRCV);
152014b4041Sbriggs scsi_clear_irq();
153e46e8e7aSbriggs }
154e46e8e7aSbriggs
155e46e8e7aSbriggs static void
scsi_mach_init(struct ncr_softc * sc)1567acd68b1Schs scsi_mach_init(struct ncr_softc *sc)
157e46e8e7aSbriggs {
158e46e8e7aSbriggs static int initted = 0;
159e46e8e7aSbriggs
160e46e8e7aSbriggs if (initted++)
1610f09ed48Sprovos panic("scsi_mach_init called again.");
162e46e8e7aSbriggs
163e46e8e7aSbriggs ncr = (volatile u_char *)
164e46e8e7aSbriggs (SCSIBase + (u_long) ncr);
165e46e8e7aSbriggs ncr_5380_with_drq = (volatile u_char *)
166e46e8e7aSbriggs (SCSIBase + (u_int) ncr_5380_with_drq);
167e46e8e7aSbriggs ncr_5380_without_drq = (volatile u_char *)
168e46e8e7aSbriggs (SCSIBase + (u_int) ncr_5380_without_drq);
169a7783604Sbriggs
170014b4041Sbriggs if (VIA2 == VIA2OFF) {
171a7783604Sbriggs scsi_enable = Via1Base + VIA2 * 0x2000 + vIER;
172014b4041Sbriggs scsi_flag = Via1Base + VIA2 * 0x2000 + vIFR;
173014b4041Sbriggs } else {
174a7783604Sbriggs scsi_enable = Via1Base + VIA2 * 0x2000 + rIER;
175014b4041Sbriggs scsi_flag = Via1Base + VIA2 * 0x2000 + rIFR;
176014b4041Sbriggs }
177a7783604Sbriggs
178215c0b89Sscottr via2_register_irq(VIA2_SCSIIRQ, ncr5380_irq_intr, sc);
179215c0b89Sscottr via2_register_irq(VIA2_SCSIDRQ, ncr5380_drq_intr, sc);
180e46e8e7aSbriggs }
181e46e8e7aSbriggs
182e46e8e7aSbriggs static int
machine_match(device_t parent,cfdata_t cf,void * aux,struct cfdriver * cd)183cbab9cadSchs machine_match(device_t parent, cfdata_t cf, void *aux,
1847acd68b1Schs struct cfdriver *cd)
185e46e8e7aSbriggs {
186e46e8e7aSbriggs if (!mac68k_machine.scsi80)
187e46e8e7aSbriggs return 0;
188e46e8e7aSbriggs return 1;
189e46e8e7aSbriggs }
190e46e8e7aSbriggs
191e46e8e7aSbriggs #if USE_PDMA
192e46e8e7aSbriggs int pdma_5380_dir = 0;
193e46e8e7aSbriggs
194a7783604Sbriggs u_char *pending_5380_data;
195a7783604Sbriggs u_long pending_5380_count;
196e46e8e7aSbriggs
197229c36d3Sbriggs #define NCR5380_PDMA_DEBUG 1 /* Maybe we try with this off eventually. */
198e23598f2Sbriggs
199229c36d3Sbriggs #if NCR5380_PDMA_DEBUG
200e46e8e7aSbriggs int pdma_5380_sends = 0;
201bee422d9Sbriggs int pdma_5380_bytes = 0;
202e46e8e7aSbriggs
203e46e8e7aSbriggs void
pdma_stat(void)2047acd68b1Schs pdma_stat(void)
205e46e8e7aSbriggs {
20640ecbf8eSchristos printf("PDMA SCSI: %d xfers completed for %d bytes.\n",
207a7783604Sbriggs pdma_5380_sends, pdma_5380_bytes);
20840ecbf8eSchristos printf("pdma_5380_dir = %d\t",
209a7783604Sbriggs pdma_5380_dir);
21040ecbf8eSchristos printf("datap = %p, remainder = %ld.\n",
211e46e8e7aSbriggs pending_5380_data, pending_5380_count);
212229c36d3Sbriggs scsi_show();
213e46e8e7aSbriggs }
214e46e8e7aSbriggs #endif
215e46e8e7aSbriggs
216e46e8e7aSbriggs void
pdma_cleanup(void)217bee422d9Sbriggs pdma_cleanup(void)
218bee422d9Sbriggs {
219bee422d9Sbriggs SC_REQ *reqp = connected;
22037163421Sbriggs int s;
221bee422d9Sbriggs
222bee422d9Sbriggs s = splbio();
2232a878c9aSbriggs PID("pdma_cleanup0");
224bee422d9Sbriggs
225a7783604Sbriggs pdma_5380_dir = 0;
226bee422d9Sbriggs
227229c36d3Sbriggs #if NCR5380_PDMA_DEBUG
228bee422d9Sbriggs pdma_5380_sends++;
229bee422d9Sbriggs pdma_5380_bytes+=(reqp->xdata_len - pending_5380_count);
230bee422d9Sbriggs #endif
231bee422d9Sbriggs
232bee422d9Sbriggs /*
233bee422d9Sbriggs * Update pointers.
234bee422d9Sbriggs */
235bee422d9Sbriggs reqp->xdata_ptr += reqp->xdata_len - pending_5380_count;
236bee422d9Sbriggs reqp->xdata_len = pending_5380_count;
237bee422d9Sbriggs
238bee422d9Sbriggs /*
239bee422d9Sbriggs * Reset DMA mode.
240bee422d9Sbriggs */
241bee422d9Sbriggs SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
242bee422d9Sbriggs
243bee422d9Sbriggs /*
244e23598f2Sbriggs * Clear any pending interrupts.
245e23598f2Sbriggs */
246e23598f2Sbriggs scsi_clr_ipend();
247e23598f2Sbriggs
248e23598f2Sbriggs /*
249bee422d9Sbriggs * Tell interrupt functions that DMA has ended.
250bee422d9Sbriggs */
251bee422d9Sbriggs reqp->dr_flag &= ~DRIVER_IN_DMA;
252bee422d9Sbriggs
253bee422d9Sbriggs SET_5380_REG(NCR5380_MODE, IMODE_BASE);
254bee422d9Sbriggs SET_5380_REG(NCR5380_ICOM, 0);
255bee422d9Sbriggs
256bee422d9Sbriggs splx(s);
257bee422d9Sbriggs
258bee422d9Sbriggs /*
259bee422d9Sbriggs * Back for more punishment.
260bee422d9Sbriggs */
2612a878c9aSbriggs PID("pdma_cleanup1");
262bee422d9Sbriggs run_main(cur_softc);
2632a878c9aSbriggs PID("pdma_cleanup2");
264bee422d9Sbriggs }
26523216939Sbriggs #endif
266bee422d9Sbriggs
267a783fa47Smrg static int
pdma_ready(void)2687acd68b1Schs pdma_ready(void)
269e46e8e7aSbriggs {
27023216939Sbriggs #if USE_PDMA
27123216939Sbriggs SC_REQ *reqp = connected;
27223216939Sbriggs int dmstat, idstat;
27323216939Sbriggs extern u_char ncr5380_no_parchk;
27423216939Sbriggs
2752a878c9aSbriggs PID("pdma_ready0");
276a7783604Sbriggs if (pdma_5380_dir) {
2775c13e718Sbriggs PID("pdma_ready1.");
278e46e8e7aSbriggs /*
279e46e8e7aSbriggs * For a phase mis-match, ATN is a "don't care," IRQ is 1 and
280e46e8e7aSbriggs * all other bits in the Bus & Status Register are 0. Also,
281e46e8e7aSbriggs * the current SCSI Bus Status Register has a 1 for BSY and
282e46e8e7aSbriggs * REQ. Since we're just checking that this interrupt isn't a
283e46e8e7aSbriggs * reselection or a reset, we just check for either.
284e46e8e7aSbriggs */
285014b4041Sbriggs dmstat = GET_5380_REG(NCR5380_DMSTAT);
28623216939Sbriggs idstat = GET_5380_REG(NCR5380_IDSTAT);
28723216939Sbriggs if ( ((dmstat & (0xff & ~SC_ATN_STAT)) == SC_IRQ_SET)
28823216939Sbriggs && ((idstat & (SC_S_BSY|SC_S_REQ))
28923216939Sbriggs == (SC_S_BSY | SC_S_REQ)) ) {
290014b4041Sbriggs PID("pdma_ready2");
29123216939Sbriggs pdma_cleanup();
29223216939Sbriggs return 1;
29323216939Sbriggs } else if (PH_IN(reqp->phase) && (dmstat & SC_PAR_ERR)) {
29423216939Sbriggs if (!(ncr5380_no_parchk & (1 << reqp->targ_id)))
29523216939Sbriggs /* XXX: Should be parity error ???? */
29623216939Sbriggs reqp->xs->error = XS_DRIVER_STUFFUP;
297014b4041Sbriggs PID("pdma_ready3");
29823216939Sbriggs /* XXX: is this the right reaction? */
29923216939Sbriggs pdma_cleanup();
30023216939Sbriggs return 1;
30123216939Sbriggs } else if ( !(idstat & SC_S_REQ)
30223216939Sbriggs || (((idstat>>2) & 7) != reqp->phase)) {
30323216939Sbriggs #ifdef DIAGNOSTIC
30423216939Sbriggs /* XXX: is this the right reaction? Can this happen? */
30523216939Sbriggs scsi_show();
30640ecbf8eSchristos printf("Unexpected phase change.\n");
30723216939Sbriggs #endif
30823216939Sbriggs reqp->xs->error = XS_DRIVER_STUFFUP;
309bee422d9Sbriggs pdma_cleanup();
310e60752e5Sbriggs return 1;
311bee422d9Sbriggs } else {
312e46e8e7aSbriggs scsi_show();
3130f09ed48Sprovos panic("Spurious interrupt during PDMA xfer.");
314e46e8e7aSbriggs }
3152a878c9aSbriggs } else
316014b4041Sbriggs PID("pdma_ready4");
31723216939Sbriggs #endif
318e60752e5Sbriggs return 0;
319e60752e5Sbriggs }
320e60752e5Sbriggs
321014b4041Sbriggs static void
ncr5380_irq_intr(void * p)3227acd68b1Schs ncr5380_irq_intr(void *p)
323e60752e5Sbriggs {
3242a878c9aSbriggs PID("irq");
325014b4041Sbriggs
32623216939Sbriggs #if USE_PDMA
3274dc81200Sbriggs if (pdma_ready()) {
328e60752e5Sbriggs return;
329e60752e5Sbriggs }
33023216939Sbriggs #endif
331e46e8e7aSbriggs scsi_idisable();
332e46e8e7aSbriggs ncr_ctrl_intr(cur_softc);
333e46e8e7aSbriggs }
334e46e8e7aSbriggs
335a7783604Sbriggs /*
336e23598f2Sbriggs * This is the meat of the PDMA transfer.
337e23598f2Sbriggs * When we get here, we shove data as fast as the mac can take it.
338e23598f2Sbriggs * We depend on several things:
339e23598f2Sbriggs * * All macs after the Mac Plus that have a 5380 chip should have a general
340e23598f2Sbriggs * logic IC that handshakes data for blind transfers.
341e23598f2Sbriggs * * If the SCSI controller finishes sending/receiving data before we do,
342e23598f2Sbriggs * the same general logic IC will generate a /BERR for us in short order.
343e23598f2Sbriggs * * The fault address for said /BERR minus the base address for the
344e23598f2Sbriggs * transfer will be the amount of data that was actually written.
345e23598f2Sbriggs *
346e23598f2Sbriggs * We use the nofault flag and the setjmp/longjmp in locore.s so we can
347e23598f2Sbriggs * detect and handle the bus error for early termination of a command.
348e23598f2Sbriggs * This is usually caused by a disconnecting target.
349a7783604Sbriggs */
350014b4041Sbriggs static void
do_ncr5380_drq_intr(void * p)3517acd68b1Schs do_ncr5380_drq_intr(void *p)
352e46e8e7aSbriggs {
353e46e8e7aSbriggs #if USE_PDMA
3540b7e64bbSscottr extern int *nofault, m68k_fault_addr;
355e23598f2Sbriggs label_t faultbuf;
356e23598f2Sbriggs register int count;
357e23598f2Sbriggs volatile u_int32_t *long_drq;
358e23598f2Sbriggs u_int32_t *long_data;
359652316b5Smartin volatile u_int8_t *drq;
360e23598f2Sbriggs u_int8_t *data;
361e23598f2Sbriggs
3622a878c9aSbriggs #if DBG_PID
3632a878c9aSbriggs if (pdma_5380_dir == 2) {
3642a878c9aSbriggs PID("drq (in)");
3652a878c9aSbriggs } else {
3662a878c9aSbriggs PID("drq (out)");
3672a878c9aSbriggs }
368e46e8e7aSbriggs #endif
369e23598f2Sbriggs
370e46e8e7aSbriggs /*
371e23598f2Sbriggs * Setup for a possible bus error caused by SCSI controller
372e23598f2Sbriggs * switching out of DATA-IN/OUT before we're done with the
373e23598f2Sbriggs * current transfer.
374e46e8e7aSbriggs */
375e23598f2Sbriggs nofault = (int *) &faultbuf;
376e23598f2Sbriggs
377e23598f2Sbriggs if (setjmp((label_t *) nofault)) {
3782a878c9aSbriggs PID("drq berr");
379e23598f2Sbriggs nofault = (int *) 0;
3800b7e64bbSscottr count = ( (u_long) m68k_fault_addr
381e23598f2Sbriggs - (u_long) ncr_5380_with_drq);
382e23598f2Sbriggs if ((count < 0) || (count > pending_5380_count)) {
38340ecbf8eSchristos printf("pdma %s: cnt = %d (0x%x) (pending cnt %ld)\n",
3849a1fb267Sbriggs (pdma_5380_dir == 2) ? "in" : "out",
3859a1fb267Sbriggs count, count, pending_5380_count);
386e23598f2Sbriggs panic("something is wrong");
387e23598f2Sbriggs }
388e23598f2Sbriggs
389e23598f2Sbriggs pending_5380_data += count;
390e23598f2Sbriggs pending_5380_count -= count;
391e23598f2Sbriggs
3920b7e64bbSscottr m68k_fault_addr = 0;
393014b4041Sbriggs
394014b4041Sbriggs PID("end drq early");
395014b4041Sbriggs
396bee422d9Sbriggs return;
397e46e8e7aSbriggs }
398e23598f2Sbriggs
399e23598f2Sbriggs if (pdma_5380_dir == 2) { /* Data In */
400e23598f2Sbriggs int resid;
401e23598f2Sbriggs
402e23598f2Sbriggs /*
403e23598f2Sbriggs * Get the dest address aligned.
404e23598f2Sbriggs */
405*d1579b2dSriastradh resid = count = uimin(pending_5380_count,
406229c36d3Sbriggs 4 - (((int) pending_5380_data) & 0x3));
407229c36d3Sbriggs if (count && (count < 4)) {
408e23598f2Sbriggs data = (u_int8_t *) pending_5380_data;
40961f16670Sjmc drq = (volatile u_int8_t *) ncr_5380_with_drq;
410e23598f2Sbriggs while (count) {
4117456c67dShauke *data++ = *drq++;
4127456c67dShauke count--;
413e23598f2Sbriggs }
414e23598f2Sbriggs pending_5380_data += resid;
415e23598f2Sbriggs pending_5380_count -= resid;
416e23598f2Sbriggs }
417e23598f2Sbriggs
418e23598f2Sbriggs /*
419e23598f2Sbriggs * Get ready to start the transfer.
420e23598f2Sbriggs */
42123216939Sbriggs while (pending_5380_count) {
42223216939Sbriggs int dcount;
42323216939Sbriggs
424*d1579b2dSriastradh dcount = count = uimin(pending_5380_count, MIN_PHYS);
425e23598f2Sbriggs long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
426c1138ce6Sbriggs long_data = (u_int32_t *) pending_5380_data;
427e23598f2Sbriggs
428e23598f2Sbriggs #define R4 *long_data++ = *long_drq++
42916865d71Sbriggs while ( count > 64 ) {
430e23598f2Sbriggs R4; R4; R4; R4; R4; R4; R4; R4;
431e23598f2Sbriggs R4; R4; R4; R4; R4; R4; R4; R4; /* 64 */
432014b4041Sbriggs count -= 64;
433e23598f2Sbriggs }
43416865d71Sbriggs while (count > 8) {
43516865d71Sbriggs R4; R4; count -= 8;
436e23598f2Sbriggs }
437e23598f2Sbriggs #undef R4
438e23598f2Sbriggs data = (u_int8_t *) long_data;
43961f16670Sjmc drq = (volatile u_int8_t *) long_drq;
440e23598f2Sbriggs while (count) {
4417456c67dShauke *data++ = *drq++;
4427456c67dShauke count--;
443e23598f2Sbriggs }
44423216939Sbriggs pending_5380_count -= dcount;
445c1138ce6Sbriggs pending_5380_data += dcount;
44623216939Sbriggs }
447e46e8e7aSbriggs } else {
448e23598f2Sbriggs int resid;
449e23598f2Sbriggs
450e23598f2Sbriggs /*
451e23598f2Sbriggs * Get the source address aligned.
452e23598f2Sbriggs */
453*d1579b2dSriastradh resid = count = uimin(pending_5380_count,
454229c36d3Sbriggs 4 - (((int) pending_5380_data) & 0x3));
455229c36d3Sbriggs if (count && (count < 4)) {
456e23598f2Sbriggs data = (u_int8_t *) pending_5380_data;
45761f16670Sjmc drq = (volatile u_int8_t *) ncr_5380_with_drq;
458e23598f2Sbriggs while (count) {
459e23598f2Sbriggs #define W1 *drq++ = *data++
460e23598f2Sbriggs W1; count--;
461e23598f2Sbriggs #undef W1
462e23598f2Sbriggs }
463e23598f2Sbriggs pending_5380_data += resid;
464e23598f2Sbriggs pending_5380_count -= resid;
465e23598f2Sbriggs }
466e23598f2Sbriggs
467e23598f2Sbriggs /*
468e23598f2Sbriggs * Get ready to start the transfer.
469e23598f2Sbriggs */
47023216939Sbriggs while (pending_5380_count) {
47123216939Sbriggs int dcount;
47223216939Sbriggs
473*d1579b2dSriastradh dcount = count = uimin(pending_5380_count, MIN_PHYS);
474e23598f2Sbriggs long_drq = (volatile u_int32_t *) ncr_5380_with_drq;
475c1138ce6Sbriggs long_data = (u_int32_t *) pending_5380_data;
476e23598f2Sbriggs
477e23598f2Sbriggs #define W4 *long_drq++ = *long_data++
47816865d71Sbriggs while ( count > 64 ) {
479e23598f2Sbriggs W4; W4; W4; W4; W4; W4; W4; W4;
48023216939Sbriggs W4; W4; W4; W4; W4; W4; W4; W4; /* 64 */
481e23598f2Sbriggs count -= 64;
482e23598f2Sbriggs }
48316865d71Sbriggs while ( count > 8 ) {
48416865d71Sbriggs W4; W4;
48516865d71Sbriggs count -= 8;
486e23598f2Sbriggs }
487e23598f2Sbriggs #undef W4
488e23598f2Sbriggs data = (u_int8_t *) long_data;
48961f16670Sjmc drq = (volatile u_int8_t *) long_drq;
490e23598f2Sbriggs while (count) {
491e23598f2Sbriggs #define W1 *drq++ = *data++
492e23598f2Sbriggs W1; count--;
493e23598f2Sbriggs #undef W1
494e23598f2Sbriggs }
49523216939Sbriggs pending_5380_count -= dcount;
496c1138ce6Sbriggs pending_5380_data += dcount;
49723216939Sbriggs }
49816865d71Sbriggs
499014b4041Sbriggs PID("write complete");
500014b4041Sbriggs
501652316b5Smartin (void)*((volatile u_int8_t *) ncr_5380_with_drq);
50216865d71Sbriggs
50316865d71Sbriggs PID("read a byte to force a phase change");
50416865d71Sbriggs }
50516865d71Sbriggs
506d25f63a7Sbriggs /*
507d25f63a7Sbriggs * OK. No bus error occurred above. Clear the nofault flag
508d25f63a7Sbriggs * so we no longer short-circuit bus errors.
509d25f63a7Sbriggs */
510d25f63a7Sbriggs nofault = (int *) 0;
511d25f63a7Sbriggs
5122a878c9aSbriggs PID("end drq");
513014b4041Sbriggs return;
514014b4041Sbriggs #else
515014b4041Sbriggs return;
516a7783604Sbriggs #endif /* if USE_PDMA */
517a7783604Sbriggs }
518a7783604Sbriggs
519014b4041Sbriggs static void
ncr5380_drq_intr(void * p)5207acd68b1Schs ncr5380_drq_intr(void *p)
521014b4041Sbriggs {
522014b4041Sbriggs while (GET_5380_REG(NCR5380_DMSTAT) & SC_DMA_REQ) {
523014b4041Sbriggs do_ncr5380_drq_intr(p);
524014b4041Sbriggs scsi_clear_drq();
525014b4041Sbriggs }
526014b4041Sbriggs }
527014b4041Sbriggs
528a7783604Sbriggs #if USE_PDMA
529e46e8e7aSbriggs
530e46e8e7aSbriggs #define SCSI_TIMEOUT_VAL 10000000
531e46e8e7aSbriggs
532e46e8e7aSbriggs static int
transfer_pdma(u_char * phasep,u_char * data,u_long * count)5337acd68b1Schs transfer_pdma(u_char *phasep, u_char *data, u_long *count)
534e46e8e7aSbriggs {
535e46e8e7aSbriggs SC_REQ *reqp = connected;
53637163421Sbriggs int len = *count, s, scsi_timeout = SCSI_TIMEOUT_VAL;
537e46e8e7aSbriggs
538a7783604Sbriggs if (pdma_5380_dir) {
539e46e8e7aSbriggs panic("ncrscsi: transfer_pdma called when operation already "
5400f09ed48Sprovos "pending.");
541e46e8e7aSbriggs }
5422a878c9aSbriggs PID("transfer_pdma0")
543e46e8e7aSbriggs
544bee422d9Sbriggs /*
545e23598f2Sbriggs * Don't bother with PDMA if we can't sleep or for small transfers.
546bee422d9Sbriggs */
547a106882aSbriggs if (reqp->dr_flag & DRIVER_NOINT) {
5482a878c9aSbriggs PID("pdma, falling back to transfer_pio.")
549d8dc3d91Sbriggs transfer_pio(phasep, data, count, 0);
550bee422d9Sbriggs return -1;
551e46e8e7aSbriggs }
552e46e8e7aSbriggs
553e46e8e7aSbriggs /*
554bee422d9Sbriggs * We are probably already at spl2(), so this is likely a no-op.
555bee422d9Sbriggs * Paranoia.
556bee422d9Sbriggs */
557bee422d9Sbriggs s = splbio();
558bee422d9Sbriggs
559e23598f2Sbriggs scsi_idisable();
560e23598f2Sbriggs
561e23598f2Sbriggs /*
562e23598f2Sbriggs * Match phases with target.
563e23598f2Sbriggs */
564e23598f2Sbriggs SET_5380_REG(NCR5380_TCOM, *phasep);
565e23598f2Sbriggs
566bee422d9Sbriggs /*
567bee422d9Sbriggs * Clear pending interrupts.
568bee422d9Sbriggs */
569e46e8e7aSbriggs scsi_clr_ipend();
570e46e8e7aSbriggs
571e46e8e7aSbriggs /*
572e46e8e7aSbriggs * Wait until target asserts BSY.
573e46e8e7aSbriggs */
574e23598f2Sbriggs while ( ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) == 0)
575e23598f2Sbriggs && (--scsi_timeout) );
576e46e8e7aSbriggs if (!scsi_timeout) {
577e46e8e7aSbriggs #if DIAGNOSTIC
57840ecbf8eSchristos printf("scsi timeout: waiting for BSY in %s.\n",
579e23598f2Sbriggs (*phasep == PH_DATAOUT) ? "pdma_out" : "pdma_in");
580e46e8e7aSbriggs #endif
581e46e8e7aSbriggs goto scsi_timeout_error;
582e46e8e7aSbriggs }
583e46e8e7aSbriggs
584e46e8e7aSbriggs /*
585bee422d9Sbriggs * Tell the driver that we're in DMA mode.
586bee422d9Sbriggs */
587bee422d9Sbriggs reqp->dr_flag |= DRIVER_IN_DMA;
588bee422d9Sbriggs
589bee422d9Sbriggs /*
590a7783604Sbriggs * Load transfer values for DRQ interrupt handlers.
591e46e8e7aSbriggs */
592a7783604Sbriggs pending_5380_data = data;
593e46e8e7aSbriggs pending_5380_count = len;
594e46e8e7aSbriggs
595e46e8e7aSbriggs /*
596e46e8e7aSbriggs * Set the transfer function to be called on DRQ interrupts.
597bee422d9Sbriggs * And note that we're waiting.
598e46e8e7aSbriggs */
599a7783604Sbriggs switch (*phasep) {
600a7783604Sbriggs default:
6010f09ed48Sprovos panic("Unexpected phase in transfer_pdma.");
602a7783604Sbriggs case PH_DATAOUT:
603a7783604Sbriggs pdma_5380_dir = 1;
604229c36d3Sbriggs SET_5380_REG(NCR5380_ICOM, GET_5380_REG(NCR5380_ICOM)|SC_ADTB);
605229c36d3Sbriggs SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
606e23598f2Sbriggs SET_5380_REG(NCR5380_DMSTAT, 0);
607a7783604Sbriggs break;
608a7783604Sbriggs case PH_DATAIN:
609a7783604Sbriggs pdma_5380_dir = 2;
610229c36d3Sbriggs SET_5380_REG(NCR5380_ICOM, 0);
611229c36d3Sbriggs SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE)|SC_M_DMA);
612e46e8e7aSbriggs SET_5380_REG(NCR5380_IRCV, 0);
613e23598f2Sbriggs break;
614e46e8e7aSbriggs }
615e46e8e7aSbriggs
6162a878c9aSbriggs PID("waiting for interrupt.")
617229c36d3Sbriggs
618e46e8e7aSbriggs /*
619e46e8e7aSbriggs * Now that we're set up, enable interrupts and drop processor
620bee422d9Sbriggs * priority back down.
621e46e8e7aSbriggs */
622e46e8e7aSbriggs scsi_ienable();
623e46e8e7aSbriggs splx(s);
624bee422d9Sbriggs return 0;
625e46e8e7aSbriggs
626e46e8e7aSbriggs scsi_timeout_error:
627e46e8e7aSbriggs /*
628e46e8e7aSbriggs * Clear the DMA mode.
629e46e8e7aSbriggs */
630e46e8e7aSbriggs SET_5380_REG(NCR5380_MODE, GET_5380_REG(NCR5380_MODE) & ~SC_M_DMA);
631e46e8e7aSbriggs return -1;
632e46e8e7aSbriggs }
633e46e8e7aSbriggs #endif /* if USE_PDMA */
634e46e8e7aSbriggs
635e46e8e7aSbriggs /* Include general routines. */
636166af003Sbriggs #include <mac68k/dev/ncr5380.c>
637